Packages

library(tidyverse)
library(ggrepel)
library(extraDistr)   # install.packages("extraDistr")
library(HDInterval)   # install.packages("HDInterval")
library(tidybayes)    # install.packages("tidybayes")
library(bayesplot)    # install.packages("bayesplot")
library(modelr)
library(broom.mixed)  # install.packages("broom.mixed")
library(brms)         # install.packages("brms")
library(ggthemes)
library(patchwork)
theme_set(theme_minimal())

# Creating a theme function used for visualizations
theme_clean <- function() {
  theme_minimal(base_family = "Arial") +
    theme(panel.grid.minor = element_blank(),
          plot.title = element_text(face = "bold"),
          axis.title = element_text(face = "bold"),
          strip.text = element_text(face = "bold", size = rel(1), hjust = 0),
          strip.background = element_rect(fill = "grey80", color = NA),
          legend.title = element_text(face = "bold"))
}

Background

This study is a follow-up analysis of our previous work examining the predictive value of acoustic and kinematic measures in predicting intelligibility and articulatory precision in speakers with and without Parkinson’s disease (PD; https://osf.io/hfuq5/).

Our previous findings indicated that among several measures, vowel space area (VSA), and kinematic distance were the best predictors of both intelligibility and articulatory precision. However, this relationship was examined using pooled data, without considering differences in speaking group (control vs. PD) or condition (conversational vs. clear). Therefore, it remains unknown how speakers with and without dysarthria due to PD differ in terms of intelligibility, articulatory precision, VSA, and kinematic distance. Additionally, it is unclear how these groups respond to prompts to speak more clearly. Thus, the following research questions were posed:

  1. How do speakers with and without PD of varying dysarthria severity levels differ in terms of intelligibility, articulatory precision, vowel space area (VSA), and kinematic distance? (Group Effects)
  2. When prompted to speak more clearly, how do speakers with and without PD of varying dysarthria severities modify their articulation (VSA and kinematic distance), and does this cue result in perceptual gains in intelligibility and articulatory precision? (Group × Condition Interaction Effects)

Data Analysis

Before we can build our models, we’ll need some information about the speakers.

speakerList <-
  rio::import(file = "https://raw.githubusercontent.com/AustinRThompson/multidomain-vowelArtic-PD/main/Data/PreppedData/Speaker%20List_Clean.csv") %>%
  
  # Making sure dxTime is numeric
  dplyr::mutate(dxTime = as.numeric(dxTime)) %>%
  
  # Refactoring Sex
  dplyr::mutate(Sex = factor(
    Sex,
    levels = c("M",
               "F"),
    labels = c("Male Speakers",
               "Female Speakers")
  )) %>%
  
  # Removing the MoCA Scores - Not all speakers had them
  dplyr::select(!MoCA)

Intelligibility

Intelligibility was collected through ratings obtained through a listener survey. They would listen to a speaker, and then rate how intelligible the speaker was using a horizontally oriented visual analog scale. The left end of the scale was labeled “Cannot understand anything” and corresponded to a value of 0. The right end of the scale was labeled “Understood everything” and corresponded to a value of 100.

While any value between 0 and 100 could be selected, listeners tended to rate on the extreme ends, resulting in a beta distribution. Therefore, for this model, we used a beta family for our model. But first, we rescaled the intelligibility measure to fall between 0 and 1, excluding the endpoint values of 0 and 1. ### Loading the data

perceptualMeasures <- rio::import(file = "https://raw.githubusercontent.com/AustinRThompson/multidomain-vowelArtic-PD/main/Data/PreppedData/ListenerData/ListenerRatings_allRatings.csv") %>%
  dplyr::select(!V1) %>%
  dplyr::filter(ratingType == "Int") %>% # We only want the intelligibility ratings for this model
  dplyr::filter(condition != "lessClear") %>% # We won't use the less clear condition in this study
  
  # Here we rename some variables and clean up the factors
  dplyr::rename(Int = Rating) %>%
  dplyr::mutate(Sex = factor(Sex, levels = c("M", "F")),
                condition = factor(condition, levels = c("conv", "moreClear"))) %>%
  
  # Now we merge the intelligibility ratings with the speakerList, which has information about severity level.
  base::merge(., speakerList %>%
                dplyr::select(StudyID, Severity)) %>%
  dplyr::mutate(
    Severity = factor(
      Severity,
      levels = c("HC", "Mild", "Moderate", "Severe", "Profound"),
      labels = c("Control", "Mild", "Moderate", "Severe", "Profound")
    )
  ) %>%
  dplyr::relocate(Severity, .after = Group)

# Lets visualize the outcome measure, intelligibility
hist(perceptualMeasures$Int)


# Here, we rescale the measure to fit a beta distribtion
epsilon <- 1e-5
data_modelData_Int <- perceptualMeasures %>%
  dplyr::select(StudyID,
                Group,
                Sex,
                Age,
                Severity,
                condition,
                Sent,
                rep,
                ListenerID,
                Int) %>%
  dplyr::mutate(
    Int = Int / 100,
    # the following makes sure that 0 and 1 are not included in the beta distribution
    Int = Int * ((nrow(.) - 1) + .5) / nrow(.),
    Int = Int * (1 - 2 * epsilon) + epsilon
  )

performance::check_distribution(data_modelData_Int$Int)
# Predicted Distribution of Vector

  Distribution Probability
          beta         56%
     bernoulli         12%
 beta-binomial          9%
# Taking out the trash
rm(perceptualMeasures, epsilon)

Priors

First, we need to figure out the model parameters


modelFormula_Int <-
  Int ~ Severity * condition +
  (1 | StudyID / Sent / rep) + # Each Speaker (StudyID) read three sentences (Sent), five times each (rep)
  (1 | ListenerID)

brms::get_prior(
  modelFormula_Int, 
  data = data_modelData_Int, 
  family = Beta)
                prior     class                                coef            group resp dpar nlpar lb ub       source
               (flat)         b                                                                                 default
               (flat)         b                  conditionmoreClear                                        (vectorized)
               (flat)         b                        SeverityMild                                        (vectorized)
               (flat)         b     SeverityMild:conditionmoreClear                                        (vectorized)
               (flat)         b                    SeverityModerate                                        (vectorized)
               (flat)         b SeverityModerate:conditionmoreClear                                        (vectorized)
               (flat)         b                    SeverityProfound                                        (vectorized)
               (flat)         b SeverityProfound:conditionmoreClear                                        (vectorized)
               (flat)         b                      SeveritySevere                                        (vectorized)
               (flat)         b   SeveritySevere:conditionmoreClear                                        (vectorized)
 student_t(3, 0, 2.5) Intercept                                                                                 default
    gamma(0.01, 0.01)       phi                                                                       0         default
 student_t(3, 0, 2.5)        sd                                                                       0         default
 student_t(3, 0, 2.5)        sd                                           ListenerID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept       ListenerID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                              StudyID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept          StudyID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                         StudyID:Sent                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept     StudyID:Sent                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                     StudyID:Sent:rep                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept StudyID:Sent:rep                  0    (vectorized)

Now we can specify weakly informative priors.

prior_Int <- c(
  prior(normal(0, 10), class = Intercept), # start with larger value - 10
  prior(normal(0, 10), class = b),
  prior(cauchy(0, 10), class = sd), # paper on variance priors: https://projecteuclid.org/journals/bayesian-analysis/volume-1/issue-3/Prior-distributions-for-variance-parameters-in-hierarchical-models-comment-on/10.1214/06-BA117A.full - check 95% interval for cauchy - very large upper bound 10
  prior(gamma(1, 0.5), class = phi) # Phi = 1, mu = .5
)

Building the model

model_Int <- brms::brm(
  formula = modelFormula_Int,
  data = data_modelData_Int,
  prior = prior_Int,
  family = Beta,
  chains = 4,
  cores = 4,
  iter = 4000,
  warmup = 1000,
  control = list(adapt_delta = 0.95),
  file = "Models/brms_Int.rds",
  file_refit = "on_change"
)

Model Summary

# Probability of direction (pd)
pd_Int <- bayestestR::p_direction(model_Int) %>%
  dplyr::rename(term = Parameter,
                effect = Effects,
                component = Component) %>%
  dplyr::mutate(
    component = ifelse(component == "conditional", "cond", component),
    term = gsub(pattern = "b_", replacement = "", term),
    term = ifelse(term == "Intercept", "(Intercept)", term))

# Model results
modelSummary_Int <- tidy(model_Int) %>%
  dplyr::rename(l_95_CI = conf.low,
                u_95_CI = conf.high) %>%
  dplyr::mutate(order = row_number()) %>%
  base::merge(.,pd_Int, all = T) %>%
  dplyr::arrange(order) %>%
  dplyr::select(!order) %>%
  dplyr::mutate(
    estimate_natScale = plogis(estimate),
    l_95_CI_natScale = plogis(l_95_CI),
    u_95_CI_natScale = plogis(u_95_CI),
    robust = case_when(
      as.integer(!(l_95_CI <= 0 & u_95_CI > 0)) == 1 & pd > .95 ~ "robust",
      TRUE ~ "not robust"
    )
  )

rm(pd_Int)

Model Diagnostics

# Assess chain mixing
plot_chainMix_Int <- base::plot(model_Int, ask=FALSE)


# Posterior predictive check
plot_ppCheck_Int <- brms::pp_check(model_Int, ndraws = 1000)

# Plot conditional effects
plot_conditionalEffects_Int <- base::plot(conditional_effects(model_Int), ask = FALSE)


# Interval Estimations
data_posterior_Int <- as.matrix(model_Int) %>%
  as.data.frame()

plot_intervalEst_Int <- mcmc_areas(
  data_posterior_Int,
  pars = fixed_effects <- data_posterior_Int %>%
    as.data.frame() %>%
    dplyr::select(starts_with("b_")) %>%
    colnames(),
  # arbitrary threshold for shading probability mass
  prob = 0.95
) 

Visualizations


# Generate expected predictions from the posterio
data_posterior_Int <- model_Int %>%
  tidybayes::epred_draws(
    newdata = tidyr::expand_grid(
      Severity = c("Control", "Mild", "Moderate", "Severe", "Profound"),
      condition = c("conv", "moreClear")
    ),
    re_formula = NA
  ) %>%
  dplyr::mutate(Severity = factor(
    Severity,
    levels = c("Control", "Mild", "Moderate", "Severe", "Profound")
  ),
  condition = factor(condition,
                     levels = c("conv","moreClear"),
                     labels = c("conversational", "clear")))

plot_grandMean_Int <- ggplot(data_posterior_Int, 
                                   aes(x = .epred, y = Severity, 
                                       fill = condition)) +
  stat_halfeye() +
  ggokabeito::scale_fill_okabe_ito() +
  labs(x = "Predicted intelligibility rating", y = NULL,
       fill = "Condition",
       subtitle = "Posterior predictions") +
  scale_y_discrete(limits = rev) +
  coord_cartesian(xlim = c(0,1)) +
  theme_clean() +
  theme(legend.position = "bottom")

epsilon <- 1e-5
data_me_Int <- model_Int %>%
  emmeans::emmeans( ~ condition | Severity,
                    #at = list(Severity = "Profound"),
                    epred = TRUE,
                    re_formula = NA,
                    ) %>%
  emmeans::contrast(method = "revpairwise") %>%
  gather_emmeans_draws() %>%
  dplyr::mutate(
    .value = (.value - epsilon) / (1 - 2 * epsilon),
    # Step 1 & 2: Reverse the offset and scaling
    .value = .value * nrow(.) / ((nrow(.) - 1) + .5)
  )


plot_ame_Int <- ggplot(data_me_Int, aes(x = .value, y = Severity)) +
  stat_halfeye(fill = ggokabeito::palette_okabe_ito(order = 7)) +
  labs(x = "Average marginal effect of condition",
       y = NULL,
       subtitle = "Condition effect (clear - conversational)") +
  scale_y_discrete(limits = rev) +
  theme_clean() +
  theme(legend.position = "bottom")

# Combined plot
plot_Int <- (plot_grandMean_Int | plot_ame_Int) +
  plot_annotation(title = "Intelligibility",
                  subtitle = "Intelligibility ratings across group/severity and speaking conditions.",
                  theme = theme_clean())
ggsave(
  plot = plot_Int,
  filename = "Plots/plot_Int.png",
  height = 6,
  width = 8,
  unit = "in",
  scale = 1,
  bg = "white"
)

Articulatory Precision

Articulatory precision was collected in the same way as intelligibility ratings. They were collected through ratings obtained through a listener survey. They would listen to a speaker, and then rate how precise the speaker was using a horizontally oriented visual analog scale. The left end of the scale was labeled “imprecise or mumbled” and corresponded to a value of 0. The right end of the scale was labeled “precise or clear” and corresponded to a value of 100.

While any value between 0 and 100 could be selected, listeners tended to rate on the extreme ends, resulting in a beta distribution. Therefore, for this model, we used a beta family for our model. But first, we rescaled the precision ratings to fall between 0 and 1, excluding the endpoint values of 0 and 1.

Loading the data

perceptualMeasures <- rio::import(file = "https://raw.githubusercontent.com/AustinRThompson/multidomain-vowelArtic-PD/main/Data/PreppedData/ListenerData/ListenerRatings_allRatings.csv") %>%
  dplyr::select(!V1) %>%
  dplyr::filter(ratingType == "AP") %>% # We only want the intelligibility ratings for this model
  dplyr::filter(condition != "lessClear") %>% # We won't use the less clear condition in this study
  
  # Here we rename some variables and clean up the factors
  dplyr::rename(AP = Rating) %>%
  dplyr::mutate(Sex = factor(Sex, levels = c("M", "F")),
                condition = factor(condition, levels = c("conv", "moreClear"))) %>%
  
  # Now we merge the intelligibility ratings with the speakerList, which has information about severity level.
  base::merge(., speakerList %>%
                dplyr::select(StudyID, Severity)) %>%
  dplyr::mutate(
    Severity = factor(
      Severity,
      levels = c("HC", "Mild", "Moderate", "Severe", "Profound"),
      labels = c("Control", "Mild", "Moderate", "Severe", "Profound")
    )
  ) %>%
  dplyr::relocate(Severity, .after = Group)


# Lets visualize the outcome measure, intelligibility
hist(perceptualMeasures$AP)


# Here, we rescale the measure to fit a beta distribtion
epsilon <- 1e-5
data_modelData_AP <- perceptualMeasures %>%
  dplyr::select(StudyID,
                Group,
                Sex,
                Age,
                Severity,
                condition,
                Sent,
                rep,
                ListenerID,
                AP) %>%
  dplyr::mutate(
    AP = AP / 100,
    AP = AP * ((nrow(.) - 1) + .5) / nrow(.),
    AP = AP * (1 - 2 * epsilon) + epsilon
  ) # this makes sure that 0 and 1 are not included in the beta distribution

performance::check_distribution(data_modelData_AP$AP)
# Predicted Distribution of Vector

  Distribution Probability
          beta         59%
 beta-binomial          9%
      binomial          9%
# Taking out the trash
rm(perceptualMeasures, epsilon)

Priors

First, we need to figure out the model parameters

modelFormula_AP <- 
  AP ~ Severity*condition + 
    (1 | StudyID/Sent/rep) + # Each Speaker (StudyID) read three sentences (Sent), five times each (rep)
    (1 | ListenerID)

brms::get_prior(
  modelFormula_AP,
  data = data_modelData_AP,
  family = Beta
)
                prior     class                                coef            group resp dpar nlpar lb ub       source
               (flat)         b                                                                                 default
               (flat)         b                  conditionmoreClear                                        (vectorized)
               (flat)         b                        SeverityMild                                        (vectorized)
               (flat)         b     SeverityMild:conditionmoreClear                                        (vectorized)
               (flat)         b                    SeverityModerate                                        (vectorized)
               (flat)         b SeverityModerate:conditionmoreClear                                        (vectorized)
               (flat)         b                    SeverityProfound                                        (vectorized)
               (flat)         b SeverityProfound:conditionmoreClear                                        (vectorized)
               (flat)         b                      SeveritySevere                                        (vectorized)
               (flat)         b   SeveritySevere:conditionmoreClear                                        (vectorized)
 student_t(3, 0, 2.5) Intercept                                                                                 default
    gamma(0.01, 0.01)       phi                                                                       0         default
 student_t(3, 0, 2.5)        sd                                                                       0         default
 student_t(3, 0, 2.5)        sd                                           ListenerID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept       ListenerID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                              StudyID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept          StudyID                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                         StudyID:Sent                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept     StudyID:Sent                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                                     StudyID:Sent:rep                  0    (vectorized)
 student_t(3, 0, 2.5)        sd                           Intercept StudyID:Sent:rep                  0    (vectorized)

Now we can specify weakly informative priors.

prior_AP <- c(
  prior(normal(0, 10), class = Intercept),
  prior(normal(0, 10), class = b),
  prior(cauchy(0, 10), class = sd),
  prior(gamma(1, 0.5), class = phi) # Phi = 1, mu = .5
)

Building the model

model_AP <- brms::brm(
  formula = modelFormula_AP,
  data = data_modelData_AP,
  prior = prior_AP,
  family = Beta,
  chains = 4,
  cores = 4,
  iter = 4000,
  warmup = 1000,
  control = list(adapt_delta = 0.95),
  file = "Models/brms_AP.rds",
  file_refit = "on_change"
)

Model Summary

# Probability of direction (pd)
pd_AP <- bayestestR::p_direction(model_AP) %>%
  dplyr::rename(term = Parameter,
                effect = Effects,
                component = Component) %>%
  dplyr::mutate(
    component = ifelse(component == "conditional", "cond", component),
    term = gsub(pattern = "b_", replacement = "", term),
    term = ifelse(term == "Intercept", "(Intercept)", term))

# Model results
modelSummary_AP <- tidy(model_AP) %>%
  dplyr::rename(l_95_CI = conf.low,
                u_95_CI = conf.high) %>%
  dplyr::mutate(order = row_number()) %>%
  base::merge(.,pd_AP, all = T) %>%
  dplyr::arrange(order) %>%
  dplyr::select(!order) %>%
  dplyr::mutate(
    robust = case_when(
      as.integer(!(l_95_CI <= 0 & u_95_CI > 0)) == 1 & pd > .95 ~ "robust",
      TRUE ~ "not robust"
    )
  )

rm(pd_AP)

Model Diagnostics

# Assess chain mixing
plot_chainMix_AP <- base::plot(model_AP, ask=FALSE)


# Posterior predictive check
plot_ppCheck_AP <- brms::pp_check(model_AP, ndraws = 1000)

# Plot conditional effects
plot_conditionalEffects_AP <- base::plot(conditional_effects(model_AP), ask = FALSE)


# APerval Estimations
data_posterior_AP <- as.matrix(model_AP) %>%
  as.data.frame()

plot_intervalEst_AP <- mcmc_areas(
  data_posterior_AP,
  pars = fixed_effects <- data_posterior_AP %>%
    as.data.frame() %>%
    dplyr::select(starts_with("b_")) %>%
    colnames(),
  # arbitrary threshold for shading probability mass
  prob = 0.95
) 

Visualizations


# Generate expected predictions from the posterio
data_posterior_AP <- model_AP %>%
  tidybayes::epred_draws(
    newdata = tidyr::expand_grid(
      Severity = c("Control", "Mild", "Moderate", "Severe", "Profound"),
      condition = c("conv", "moreClear")
    ),
    re_formula = NA
  ) %>%
  dplyr::mutate(Severity = factor(
    Severity,
    levels = c("Control", "Mild", "Moderate", "Severe", "Profound")
  ),
  condition = factor(condition,
                     levels = c("conv","moreClear"),
                     labels = c("conversational", "clear")))

plot_grandMean_AP <- ggplot(data_posterior_AP, 
                                   aes(x = .epred, y = Severity, 
                                       fill = condition)) +
  stat_halfeye() +
  ggokabeito::scale_fill_okabe_ito() +
  labs(x = "Predicted articulatory precision rating", y = NULL,
       fill = "Condition",
       subtitle = "Posterior predictions") +
  scale_y_discrete(limits = rev) +
  coord_cartesian(xlim = c(0,1)) +
  theme_clean() +
  theme(legend.position = "bottom")

epsilon <- 1e-5
data_me_AP <- model_AP %>%
  emmeans::emmeans( ~ condition | Severity,
                    #at = list(Severity = "Profound"),
                    epred = TRUE,
                    re_formula = NA,
                    ) %>%
  emmeans::contrast(method = "revpairwise") %>%
  gather_emmeans_draws() %>%
  dplyr::mutate(
    .value = (.value - epsilon) / (1 - 2 * epsilon),
    # Step 1 & 2: Reverse the offset and scaling
    .value = .value * nrow(.) / ((nrow(.) - 1) + .5)
  )


plot_ame_AP <- ggplot(data_me_AP, aes(x = .value, y = Severity)) +
  stat_halfeye(fill = ggokabeito::palette_okabe_ito(order = 7)) +
  labs(x = "Average marginal effect of condition",
       y = NULL,
       subtitle = "Condition effect (clear - conversational)") +
  scale_y_discrete(limits = rev) +
  theme_clean() +
  theme(legend.position = "bottom")

# Combined plot
plot_AP <- (plot_grandMean_AP | plot_ame_AP) +
  plot_annotation(title = "Articulatory Precision",
                  subtitle = "Predicted articulatory precision ratings across group/severity and speaking conditions.",
                  theme = theme_clean())
ggsave(
  plot = plot_AP,
  filename = "Plots/plot_AP.png",
  height = 6,
  width = 8,
  unit = "in",
  scale = 1,
  bg = "white"
)

aVSA

Acoustic Vowel Space Area (aVSA) is an acoustic measure of articulatory working space. There are known sex differences when aVSA is measured in Hz. Therefore, we will measure it in Bark to try to reduce the sex effects.

The bark transformed aVSA measure ranges from .8 - 18 Bark. So it is a measure bound by 0, with no negative values. For this reason, we will use a lognormal family. ### Loading the data

vsaMeasures <- rio::import(file = "https://raw.githubusercontent.com/AustinRThompson/multidomain-vowelArtic-PD/main/Data/PreppedData/CollatedData/TargetMeasures_vsaMeasures.csv") %>%
  dplyr::filter(condition != "lessClear") %>% # We won't use the less clear condition in this study
  
  # Here we rename some variables and clean up the factors
  dplyr::mutate(Sex = factor(Sex, levels = c("M", "F")),
                condition = factor(condition, levels = c("conv", "moreClear"))) %>%
  
  # Now we merge the data with the speakerList, which has information about severity level.
  base::merge(., speakerList %>%
                dplyr::select(StudyID, Severity)) %>%
  dplyr::mutate(
    Severity = factor(
      Severity,
      levels = c("HC", "Mild", "Moderate", "Severe", "Profound"),
      labels = c("Control", "Mild", "Moderate", "Severe", "Profound")
    )
  )

# Lets visualize the outcome measure, aVSA_bark
hist(vsaMeasures$aVSA_bark)


data_modelData_aVSA <- vsaMeasures
performance::check_distribution(data_modelData_aVSA$aVSA_bark)
# Predicted Distribution of Vector

 Distribution Probability
          chi         41%
        gamma         12%
      weibull         12%
# Taking out the trash
rm(vsaMeasures)

Priors

First, we need to figure out the model parameters

modelFormula_aVSA <- 
  aVSA_bark ~ 
  Severity * condition +
  (1 | StudyID) # Here, we only have one aVSA value per speaker and condition

brms::get_prior(
  formula = modelFormula_aVSA,
  data = data_modelData_aVSA,
  family = lognormal())
                  prior     class                                coef   group resp dpar nlpar lb ub       source
                 (flat)         b                                                                        default
                 (flat)         b                  conditionmoreClear                               (vectorized)
                 (flat)         b                        SeverityMild                               (vectorized)
                 (flat)         b     SeverityMild:conditionmoreClear                               (vectorized)
                 (flat)         b                    SeverityModerate                               (vectorized)
                 (flat)         b SeverityModerate:conditionmoreClear                               (vectorized)
                 (flat)         b                    SeverityProfound                               (vectorized)
                 (flat)         b SeverityProfound:conditionmoreClear                               (vectorized)
                 (flat)         b                      SeveritySevere                               (vectorized)
                 (flat)         b   SeveritySevere:conditionmoreClear                               (vectorized)
 student_t(3, 1.9, 2.5) Intercept                                                                        default
   student_t(3, 0, 2.5)        sd                                                              0         default
   student_t(3, 0, 2.5)        sd                                     StudyID                  0    (vectorized)
   student_t(3, 0, 2.5)        sd                           Intercept StudyID                  0    (vectorized)
   student_t(3, 0, 2.5)     sigma                                                              0         default

Now we can specify weakly informative priors.

# specify priors in log space
priors_aVSA <- c(
  prior(normal(0, 10), class = Intercept),
  prior(normal(0, 10), class = b),
  prior(cauchy(0, 10), class = sd),
  prior(cauchy(0, 10), class = sigma)
)

Building the model


model_aVSA <- brms::brm(
  formula = modelFormula_aVSA,
  data = data_modelData_aVSA,
  family = lognormal(),
  prior = priors_aVSA,
  chains = 4,
  cores = 4,
  iter = 4000,
  warmup = 1000,
  control = list(adapt_delta = 0.95),
  file = "Models/brms_aVSA.rds",
  file_refit = "on_change"
)

Model Summary

# Probability of direction (pd)
pd_aVSA <- bayestestR::p_direction(model_aVSA) %>%
  dplyr::rename(term = Parameter,
                effect = Effects,
                component = Component) %>%
  dplyr::mutate(
    component = ifelse(component == "conditional", "cond", component),
    term = gsub(pattern = "b_", replacement = "", term),
    term = ifelse(term == "Intercept", "(Intercept)", term))

# Model results
modelSummary_aVSA <- tidy(model_aVSA) %>%
  dplyr::rename(l_95_CI = conf.low,
                u_95_CI = conf.high) %>%
  dplyr::mutate(order = row_number()) %>%
  base::merge(.,pd_aVSA, all = T) %>%
  dplyr::arrange(order) %>%
  dplyr::select(!order) %>%
  dplyr::mutate(
    robust = case_when(
      as.integer(!(l_95_CI <= 0 & u_95_CI > 0)) == 1 & pd > .95 ~ "robust",
      TRUE ~ "not robust"
    )
  )

rm(pd_aVSA)

Model Diagnostics

# Assess chain mixing
plot_chainMix_aVSA <- base::plot(model_aVSA, ask=FALSE)


# Posterior predictive check
plot_ppCheck_aVSA <- brms::pp_check(model_aVSA, ndraws = 1000)

# Plot conditional effects
plot_conditionalEffects_aVSA <- base::plot(conditional_effects(model_aVSA), ask = FALSE)


# aVSAerval Estimations
data_posterior_aVSA <- as.matrix(model_aVSA) %>%
  as.data.frame()

plot_intervalEst_aVSA <- mcmc_areas(
  data_posterior_aVSA,
  pars = fixed_effects <- data_posterior_aVSA %>%
    as.data.frame() %>%
    dplyr::select(starts_with("b_")) %>%
    colnames(),
  # arbitrary threshold for shading probability mass
  prob = 0.95
) 

Visualizations


# Generate expected predictions from the posterior
data_posterior_aVSA <- model_aVSA %>%
  tidybayes::epred_draws(
    newdata = tidyr::expand_grid(
      Severity = c("Control", "Mild", "Moderate", "Severe", "Profound"),
      condition = c("conv", "moreClear")
    ),
    re_formula = NA
  ) %>%
  dplyr::mutate(Severity = factor(
    Severity,
    levels = c("Control", "Mild", "Moderate", "Severe", "Profound")
  ),
  condition = factor(condition,
                     levels = c("conv","moreClear"),
                     labels = c("conversational", "clear")))

plot_grandMean_aVSA <- ggplot(data_posterior_aVSA, 
                                   aes(x = .epred, y = Severity, 
                                       fill = condition)) +
  stat_halfeye() +
  ggokabeito::scale_fill_okabe_ito() +
  labs(x = "Predicted VSA (in Bark)", y = NULL,
       fill = "Condition",
       subtitle = "Posterior predictions") +
  scale_y_discrete(limits = rev) +
  coord_cartesian(xlim = c(0,20)) +
  theme_clean() +
  theme(legend.position = "bottom")

data_me_aVSA <- model_aVSA %>%
  emmeans::emmeans( ~ condition | Severity,
                    #at = list(Severity = "Profound"),
                    epred = TRUE,
                    re_formula = NA,
                    ) %>%
  emmeans::contrast(method = "revpairwise") %>%
  gather_emmeans_draws()


plot_ame_aVSA <- ggplot(data_me_aVSA, aes(x = .value, y = Severity)) +
  stat_halfeye(fill = ggokabeito::palette_okabe_ito(order = 7)) +
  labs(x = "Average marginal effect of condition",
       y = NULL,
       subtitle = "Condition effect (clear - conversational)") +
  scale_y_discrete(limits = rev) +
  theme_clean() +
  theme(legend.position = "bottom")

# Combined plot
plot_aVSA <- (plot_grandMean_aVSA | plot_ame_aVSA) +
  plot_annotation(title = "Acoustic Vowel Space Area (VSA)",
                  subtitle = "Predicted VSA (in Bark) across group/severity and speaking conditions.",
                  theme = theme_clean())
ggsave(
  plot = plot_aVSA,
  filename = "Plots/plot_aVSA.png",
  height = 6,
  width = 8,
  unit = "in",
  scale = 1,
  bg = "white"
)

Kinematic Distance

Kinematic distance was measured from the tongue back sensor (adhered 5 mm from the tongue tip) during the diphthong /ai/ in “buy”. The 2D positions of the onset and offset were used to calculate the Euclidean distance. This measure ranges from 0.03 to 28 mm. So, it is bound by 0, and does not have any negative values. For this reason, we use the lognormal family. ### Loading the data

aiMeasures <-
  rio::import(file = "https://raw.githubusercontent.com/AustinRThompson/multidomain-vowelArtic-PD/main/Data/PreppedData/CollatedData/TargetMeasures_aiMeasures.csv") %>%
  dplyr::filter(condition != "lessClear") %>% # We won't use the less clear condition in this study
  
# Here we rename some variables and clean up the factors
  dplyr::mutate(Sex = factor(Sex, levels = c("M", "F")),
                condition = factor(condition, levels = c("conv", "moreClear"))) %>%
  
  # Now we merge the data with the speakerList, which has information about severity level.
  base::merge(., speakerList %>%
                dplyr::select(StudyID, Severity)) %>%
  dplyr::mutate(
    Severity = factor(
      Severity,
      levels = c("HC", "Mild", "Moderate", "Severe", "Profound"),
      labels = c("Control", "Mild", "Moderate", "Severe", "Profound")
    )
  ) %>%
  dplyr::group_by(StudyID, Group, Sex, Severity, condition) %>%
  dplyr::summarise(kinDistance = mean(kinDistance, na.rm = T)) %>%
  dplyr::ungroup()
`summarise()` has grouped output by 'StudyID', 'Group', 'Sex', 'Severity'. You can override using the `.groups` argument.
# Lets visualize the outcome measure, kinDistance
hist(aiMeasures$kinDistance)

hist(log(aiMeasures$kinDistance + 1))


data_modelData_kinDistance <- aiMeasures %>%
  dplyr::mutate(kinDistance = kinDistance + 1) # applying a constant before the log transformation in the model

performance::check_distribution(data_modelData_kinDistance$kinDistance)
# Predicted Distribution of Vector

 Distribution Probability
          chi         78%
  half-cauchy          6%
       normal          6%
hist(log(data_modelData_kinDistance$kinDistance))


# Taking out the trash
rm(aiMeasures)

Priors

First, we need to figure out the model parameters


modelFormula_kinDistance <-
  kinDistance ~ Severity * condition +
  (1 | StudyID) # Each Speaker (StudyID) has 2 kinDistance measures for each condition

brms::get_prior(formula = modelFormula_kinDistance,
                data = data_modelData_kinDistance,
                family = lognormal)
Warning: Rows containing NAs were excluded from the model.
                  prior     class                                coef   group resp dpar nlpar lb ub       source
                 (flat)         b                                                                        default
                 (flat)         b                  conditionmoreClear                               (vectorized)
                 (flat)         b                        SeverityMild                               (vectorized)
                 (flat)         b     SeverityMild:conditionmoreClear                               (vectorized)
                 (flat)         b                    SeverityModerate                               (vectorized)
                 (flat)         b SeverityModerate:conditionmoreClear                               (vectorized)
                 (flat)         b                    SeverityProfound                               (vectorized)
                 (flat)         b SeverityProfound:conditionmoreClear                               (vectorized)
                 (flat)         b                      SeveritySevere                               (vectorized)
                 (flat)         b   SeveritySevere:conditionmoreClear                               (vectorized)
 student_t(3, 2.6, 2.5) Intercept                                                                        default
   student_t(3, 0, 2.5)        sd                                                              0         default
   student_t(3, 0, 2.5)        sd                                     StudyID                  0    (vectorized)
   student_t(3, 0, 2.5)        sd                           Intercept StudyID                  0    (vectorized)
   student_t(3, 0, 2.5)     sigma                                                              0         default

Now we can specify weakly informative priors.

priors_kinDistance <- c(
  prior(normal(0, 10), class = Intercept),
  prior(normal(0, 10), class = b),
  prior(cauchy(0, 10), class = sigma),
  prior(cauchy(0, 10), class = sd)
)

Building the model

model_kinDistance <- brms::brm(
  formula = modelFormula_kinDistance,
  data = data_modelData_kinDistance,
  family = lognormal,
  prior = priors_kinDistance,
  chains = 4,
  cores = 4,
  iter = 4000,
  warmup = 1000,
  control = list(adapt_delta = 0.95),
  file = "Models/brms_kinDistance.rds",
  file_refit = "on_change"
)
Warning: Rows containing NAs were excluded from the model.

Model Summary

# Probability of direction (pd)
pd_kinDistance <- bayestestR::p_direction(model_kinDistance) %>%
  dplyr::rename(term = Parameter,
                effect = Effects,
                component = Component) %>%
  dplyr::mutate(
    component = ifelse(component == "conditional", "cond", component),
    term = gsub(pattern = "b_", replacement = "", term),
    term = ifelse(term == "Intercept", "(Intercept)", term))

# Model results
modelSummary_kinDistance <- tidy(model_kinDistance) %>%
  dplyr::rename(l_95_CI = conf.low,
                u_95_CI = conf.high) %>%
  dplyr::mutate(order = row_number()) %>%
  base::merge(.,pd_kinDistance, all = T) %>%
  dplyr::arrange(order) %>%
  dplyr::select(!order) %>%
  dplyr::mutate(
    robust = case_when(
      as.integer(!(l_95_CI <= 0 & u_95_CI > 0)) == 1 & pd > .95 ~ "robust",
      TRUE ~ "not robust"
    )
  )

rm(pd_kinDistance)

Model Diagnostics

# Assess chain mixing
plot_chainMix_kinDistance <- base::plot(model_kinDistance, ask=FALSE)


# Posterior predictive check
plot_ppCheck_kinDistance <- brms::pp_check(model_kinDistance, ndraws = 1000)

# Plot conditional effects
plot_conditionalEffects_kinDistance <- base::plot(conditional_effects(model_kinDistance), ask = FALSE)


# kinDistanceerval Estimations
data_posterior_kinDistance <- as.matrix(model_kinDistance) %>%
  as.data.frame()

plot_intervalEst_kinDistance <- mcmc_areas(
  data_posterior_kinDistance,
  pars = fixed_effects <- data_posterior_kinDistance %>%
    as.data.frame() %>%
    dplyr::select(starts_with("b_")) %>%
    colnames(),
  # arbitrary threshold for shading probability mass
  prob = 0.95
) 

Visualizations


# Generate expected predictions from the posterior
data_posterior_kinDistance <- model_kinDistance %>%
  tidybayes::epred_draws(
    newdata = tidyr::expand_grid(
      Severity = c("Control", "Mild", "Moderate", "Severe", "Profound"),
      condition = c("conv", "moreClear")
    ),
    re_formula = NA
  ) %>%
  dplyr::mutate(Severity = factor(
    Severity,
    levels = c("Control", "Mild", "Moderate", "Severe", "Profound")
  ),
  condition = factor(condition,
                     levels = c("conv","moreClear"),
                     labels = c("conversational", "clear")))

plot_grandMean_kinDistance <- ggplot(data_posterior_kinDistance, 
                                   aes(x = .epred, y = Severity, 
                                       fill = condition)) +
  stat_halfeye() +
  ggokabeito::scale_fill_okabe_ito() +
  labs(x = "Predicted kinematic distance (mm)", y = NULL,
       fill = "Condition",
       subtitle = "Posterior predictions") +
  scale_y_discrete(limits = rev) +
  coord_cartesian(xlim = c(0,43)) +
  theme_clean() +
  theme(legend.position = "bottom")

data_me_kinDistance <- model_kinDistance %>%
  emmeans::emmeans( ~ condition | Severity,
                    epred = TRUE,
                    re_formula = NA,
                    ) %>%
  emmeans::contrast(method = "revpairwise") %>%
  gather_emmeans_draws()


plot_ame_kinDistance <- ggplot(data_me_kinDistance, aes(x = .value, y = Severity)) +
  stat_halfeye(fill = ggokabeito::palette_okabe_ito(order = 7)) +
  labs(x = "Average marginal effect of condition",
       y = NULL,
       subtitle = "Condition effect (clear - conversational)") +
  scale_y_discrete(limits = rev) +
  theme_clean() +
  theme(legend.position = "bottom")

# Combined plot
plot_kinDistance <- (plot_grandMean_kinDistance | plot_ame_kinDistance) +
  plot_annotation(title = "Kinematic Distance",
                  subtitle = "Predicted kinematic distance (mm) for /aɪ/ across group/severity and speaking conditions.",
                  theme = theme_clean())
ggsave(
  plot = plot_kinDistance,
  filename = "Plots/plot_kinDistance.png",
  height = 6,
  width = 8,
  unit = "in",
  scale = 1,
  bg = "white"
)

Model Tables

sjPlot::tab_model(model_aVSA)
The desired updates require recompiling the model
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 5e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.5 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 4000 [  0%]  (Warmup)
Chain 1: Iteration:  400 / 4000 [ 10%]  (Warmup)
Chain 1: Iteration:  800 / 4000 [ 20%]  (Warmup)
Chain 1: Iteration: 1001 / 4000 [ 25%]  (Sampling)
Chain 1: Iteration: 1400 / 4000 [ 35%]  (Sampling)
Chain 1: Iteration: 1800 / 4000 [ 45%]  (Sampling)
Chain 1: Iteration: 2200 / 4000 [ 55%]  (Sampling)
Chain 1: Iteration: 2600 / 4000 [ 65%]  (Sampling)
Chain 1: Iteration: 3000 / 4000 [ 75%]  (Sampling)
Chain 1: Iteration: 3400 / 4000 [ 85%]  (Sampling)
Chain 1: Iteration: 3800 / 4000 [ 95%]  (Sampling)
Chain 1: Iteration: 4000 / 4000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.124 seconds (Warm-up)
Chain 1:                0.295 seconds (Sampling)
Chain 1:                0.419 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 8e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.08 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 4000 [  0%]  (Warmup)
Chain 2: Iteration:  400 / 4000 [ 10%]  (Warmup)
Chain 2: Iteration:  800 / 4000 [ 20%]  (Warmup)
Chain 2: Iteration: 1001 / 4000 [ 25%]  (Sampling)
Chain 2: Iteration: 1400 / 4000 [ 35%]  (Sampling)
Chain 2: Iteration: 1800 / 4000 [ 45%]  (Sampling)
Chain 2: Iteration: 2200 / 4000 [ 55%]  (Sampling)
Chain 2: Iteration: 2600 / 4000 [ 65%]  (Sampling)
Chain 2: Iteration: 3000 / 4000 [ 75%]  (Sampling)
Chain 2: Iteration: 3400 / 4000 [ 85%]  (Sampling)
Chain 2: Iteration: 3800 / 4000 [ 95%]  (Sampling)
Chain 2: Iteration: 4000 / 4000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.128 seconds (Warm-up)
Chain 2:                0.329 seconds (Sampling)
Chain 2:                0.457 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 1.3e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.13 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 4000 [  0%]  (Warmup)
Chain 3: Iteration:  400 / 4000 [ 10%]  (Warmup)
Chain 3: Iteration:  800 / 4000 [ 20%]  (Warmup)
Chain 3: Iteration: 1001 / 4000 [ 25%]  (Sampling)
Chain 3: Iteration: 1400 / 4000 [ 35%]  (Sampling)
Chain 3: Iteration: 1800 / 4000 [ 45%]  (Sampling)
Chain 3: Iteration: 2200 / 4000 [ 55%]  (Sampling)
Chain 3: Iteration: 2600 / 4000 [ 65%]  (Sampling)
Chain 3: Iteration: 3000 / 4000 [ 75%]  (Sampling)
Chain 3: Iteration: 3400 / 4000 [ 85%]  (Sampling)
Chain 3: Iteration: 3800 / 4000 [ 95%]  (Sampling)
Chain 3: Iteration: 4000 / 4000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.15 seconds (Warm-up)
Chain 3:                0.269 seconds (Sampling)
Chain 3:                0.419 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 6e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.06 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 4000 [  0%]  (Warmup)
Chain 4: Iteration:  400 / 4000 [ 10%]  (Warmup)
Chain 4: Iteration:  800 / 4000 [ 20%]  (Warmup)
Chain 4: Iteration: 1001 / 4000 [ 25%]  (Sampling)
Chain 4: Iteration: 1400 / 4000 [ 35%]  (Sampling)
Chain 4: Iteration: 1800 / 4000 [ 45%]  (Sampling)
Chain 4: Iteration: 2200 / 4000 [ 55%]  (Sampling)
Chain 4: Iteration: 2600 / 4000 [ 65%]  (Sampling)
Chain 4: Iteration: 3000 / 4000 [ 75%]  (Sampling)
Chain 4: Iteration: 3400 / 4000 [ 85%]  (Sampling)
Chain 4: Iteration: 3800 / 4000 [ 95%]  (Sampling)
Chain 4: Iteration: 4000 / 4000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.137 seconds (Warm-up)
Chain 4:                0.402 seconds (Sampling)
Chain 4:                0.539 seconds (Total)
Chain 4: 
LS0tCnRpdGxlOiAiVm93ZWwgQXJ0aWMgaW4gUEQ6IEJheWVzaWFuIEFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIFBhY2thZ2VzCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGV4dHJhRGlzdHIpICAgIyBpbnN0YWxsLnBhY2thZ2VzKCJleHRyYURpc3RyIikKbGlicmFyeShIREludGVydmFsKSAgICMgaW5zdGFsbC5wYWNrYWdlcygiSERJbnRlcnZhbCIpCmxpYnJhcnkodGlkeWJheWVzKSAgICAjIGluc3RhbGwucGFja2FnZXMoInRpZHliYXllcyIpCmxpYnJhcnkoYmF5ZXNwbG90KSAgICAjIGluc3RhbGwucGFja2FnZXMoImJheWVzcGxvdCIpCmxpYnJhcnkobW9kZWxyKQpsaWJyYXJ5KGJyb29tLm1peGVkKSAgIyBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbS5taXhlZCIpCmxpYnJhcnkoYnJtcykgICAgICAgICAjIGluc3RhbGwucGFja2FnZXMoImJybXMiKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHBhdGNod29yaykKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkKCiMgQ3JlYXRpbmcgYSB0aGVtZSBmdW5jdGlvbiB1c2VkIGZvciB2aXN1YWxpemF0aW9ucwp0aGVtZV9jbGVhbiA8LSBmdW5jdGlvbigpIHsKICB0aGVtZV9taW5pbWFsKGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKwogICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gcmVsKDEpLCBoanVzdCA9IDApLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gTkEpLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQp9CmBgYAoKIyBCYWNrZ3JvdW5kCgkKVGhpcyBzdHVkeSBpcyBhIGZvbGxvdy11cCBhbmFseXNpcyBvZiBvdXIgcHJldmlvdXMgd29yayBleGFtaW5pbmcgdGhlIHByZWRpY3RpdmUgdmFsdWUgb2YgYWNvdXN0aWMgYW5kIGtpbmVtYXRpYyBtZWFzdXJlcyBpbiBwcmVkaWN0aW5nIGludGVsbGlnaWJpbGl0eSBhbmQgYXJ0aWN1bGF0b3J5IHByZWNpc2lvbiBpbiBzcGVha2VycyB3aXRoIGFuZCB3aXRob3V0IFBhcmtpbnNvbidzIGRpc2Vhc2UgKFBEOyBodHRwczovL29zZi5pby9oZnVxNS8pLiAKCk91ciBwcmV2aW91cyBmaW5kaW5ncyBpbmRpY2F0ZWQgdGhhdCBhbW9uZyBzZXZlcmFsIG1lYXN1cmVzLCB2b3dlbCBzcGFjZSBhcmVhIChWU0EpLCBhbmQga2luZW1hdGljIGRpc3RhbmNlIHdlcmUgdGhlIGJlc3QgcHJlZGljdG9ycyBvZiBib3RoIGludGVsbGlnaWJpbGl0eSBhbmQgYXJ0aWN1bGF0b3J5IHByZWNpc2lvbi4gSG93ZXZlciwgdGhpcyByZWxhdGlvbnNoaXAgd2FzIGV4YW1pbmVkIHVzaW5nIHBvb2xlZCBkYXRhLCB3aXRob3V0IGNvbnNpZGVyaW5nIGRpZmZlcmVuY2VzIGluIHNwZWFraW5nIGdyb3VwIChjb250cm9sIHZzLiBQRCkgb3IgY29uZGl0aW9uIChjb252ZXJzYXRpb25hbCB2cy4gY2xlYXIpLiBUaGVyZWZvcmUsIGl0IHJlbWFpbnMgdW5rbm93biBob3cgc3BlYWtlcnMgd2l0aCBhbmQgd2l0aG91dCBkeXNhcnRocmlhIGR1ZSB0byBQRCBkaWZmZXIgaW4gdGVybXMgb2YgaW50ZWxsaWdpYmlsaXR5LCBhcnRpY3VsYXRvcnkgcHJlY2lzaW9uLCBWU0EsIGFuZCBraW5lbWF0aWMgZGlzdGFuY2UuIEFkZGl0aW9uYWxseSwgaXQgaXMgdW5jbGVhciBob3cgdGhlc2UgZ3JvdXBzIHJlc3BvbmQgdG8gcHJvbXB0cyB0byBzcGVhayBtb3JlIGNsZWFybHkuIFRodXMsIHRoZSBmb2xsb3dpbmcgcmVzZWFyY2ggcXVlc3Rpb25zIHdlcmUgcG9zZWQ6CgoxLiBIb3cgZG8gc3BlYWtlcnMgd2l0aCBhbmQgd2l0aG91dCBQRCBvZiB2YXJ5aW5nIGR5c2FydGhyaWEgc2V2ZXJpdHkgbGV2ZWxzIGRpZmZlciBpbiB0ZXJtcyBvZiBpbnRlbGxpZ2liaWxpdHksIGFydGljdWxhdG9yeSBwcmVjaXNpb24sIHZvd2VsIHNwYWNlIGFyZWEgKFZTQSksIGFuZCBraW5lbWF0aWMgZGlzdGFuY2U/IChHcm91cCBFZmZlY3RzKQoyLiBXaGVuIHByb21wdGVkIHRvIHNwZWFrIG1vcmUgY2xlYXJseSwgaG93IGRvIHNwZWFrZXJzIHdpdGggYW5kIHdpdGhvdXQgUEQgb2YgdmFyeWluZyBkeXNhcnRocmlhIHNldmVyaXRpZXMgbW9kaWZ5IHRoZWlyIGFydGljdWxhdGlvbiAoVlNBIGFuZCBraW5lbWF0aWMgZGlzdGFuY2UpLCBhbmQgZG9lcyB0aGlzIGN1ZSByZXN1bHQgaW4gcGVyY2VwdHVhbCBnYWlucyBpbiBpbnRlbGxpZ2liaWxpdHkgYW5kIGFydGljdWxhdG9yeSBwcmVjaXNpb24/IChHcm91cCDDlyBDb25kaXRpb24gSW50ZXJhY3Rpb24gRWZmZWN0cykKCgojIERhdGEgQW5hbHlzaXMKQmVmb3JlIHdlIGNhbiBidWlsZCBvdXIgbW9kZWxzLCB3ZSdsbCBuZWVkIHNvbWUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHNwZWFrZXJzLgpgYGB7cn0Kc3BlYWtlckxpc3QgPC0KICByaW86OmltcG9ydChmaWxlID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9BdXN0aW5SVGhvbXBzb24vbXVsdGlkb21haW4tdm93ZWxBcnRpYy1QRC9tYWluL0RhdGEvUHJlcHBlZERhdGEvU3BlYWtlciUyMExpc3RfQ2xlYW4uY3N2IikgJT4lCiAgCiAgIyBNYWtpbmcgc3VyZSBkeFRpbWUgaXMgbnVtZXJpYwogIGRwbHlyOjptdXRhdGUoZHhUaW1lID0gYXMubnVtZXJpYyhkeFRpbWUpKSAlPiUKICAKICAjIFJlZmFjdG9yaW5nIFNleAogIGRwbHlyOjptdXRhdGUoU2V4ID0gZmFjdG9yKAogICAgU2V4LAogICAgbGV2ZWxzID0gYygiTSIsCiAgICAgICAgICAgICAgICJGIiksCiAgICBsYWJlbHMgPSBjKCJNYWxlIFNwZWFrZXJzIiwKICAgICAgICAgICAgICAgIkZlbWFsZSBTcGVha2VycyIpCiAgKSkgJT4lCiAgCiAgIyBSZW1vdmluZyB0aGUgTW9DQSBTY29yZXMgLSBOb3QgYWxsIHNwZWFrZXJzIGhhZCB0aGVtCiAgZHBseXI6OnNlbGVjdCghTW9DQSkKYGBgCgojIyBJbnRlbGxpZ2liaWxpdHkKSW50ZWxsaWdpYmlsaXR5IHdhcyBjb2xsZWN0ZWQgdGhyb3VnaCByYXRpbmdzIG9idGFpbmVkIHRocm91Z2ggYSBsaXN0ZW5lciBzdXJ2ZXkuIFRoZXkgd291bGQgbGlzdGVuIHRvIGEgc3BlYWtlciwgYW5kIHRoZW4gcmF0ZSBob3cgaW50ZWxsaWdpYmxlIHRoZSBzcGVha2VyIHdhcyB1c2luZyBhIGhvcml6b250YWxseSBvcmllbnRlZCB2aXN1YWwgYW5hbG9nIHNjYWxlLiBUaGUgbGVmdCBlbmQgb2YgdGhlIHNjYWxlIHdhcyBsYWJlbGVkICJDYW5ub3QgdW5kZXJzdGFuZCBhbnl0aGluZyIgYW5kIGNvcnJlc3BvbmRlZCB0byBhIHZhbHVlIG9mIDAuIFRoZSByaWdodCBlbmQgb2YgdGhlIHNjYWxlIHdhcyBsYWJlbGVkICJVbmRlcnN0b29kIGV2ZXJ5dGhpbmciIGFuZCBjb3JyZXNwb25kZWQgdG8gYSB2YWx1ZSBvZiAxMDAuCgpXaGlsZSBhbnkgdmFsdWUgYmV0d2VlbiAwIGFuZCAxMDAgY291bGQgYmUgc2VsZWN0ZWQsIGxpc3RlbmVycyB0ZW5kZWQgdG8gcmF0ZSBvbiB0aGUgZXh0cmVtZSBlbmRzLCByZXN1bHRpbmcgaW4gYSBiZXRhIGRpc3RyaWJ1dGlvbi4gVGhlcmVmb3JlLCBmb3IgdGhpcyBtb2RlbCwgd2UgdXNlZCBhIGJldGEgZmFtaWx5IGZvciBvdXIgbW9kZWwuIEJ1dCBmaXJzdCwgd2UgcmVzY2FsZWQgdGhlIGludGVsbGlnaWJpbGl0eSBtZWFzdXJlIHRvIGZhbGwgYmV0d2VlbiAwIGFuZCAxLCBleGNsdWRpbmcgdGhlIGVuZHBvaW50IHZhbHVlcyBvZiAwIGFuZCAxLgojIyMgTG9hZGluZyB0aGUgZGF0YQpgYGB7cn0KcGVyY2VwdHVhbE1lYXN1cmVzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0F1c3RpblJUaG9tcHNvbi9tdWx0aWRvbWFpbi12b3dlbEFydGljLVBEL21haW4vRGF0YS9QcmVwcGVkRGF0YS9MaXN0ZW5lckRhdGEvTGlzdGVuZXJSYXRpbmdzX2FsbFJhdGluZ3MuY3N2IikgJT4lCiAgZHBseXI6OnNlbGVjdCghVjEpICU+JQogIGRwbHlyOjpmaWx0ZXIocmF0aW5nVHlwZSA9PSAiSW50IikgJT4lICMgV2Ugb25seSB3YW50IHRoZSBpbnRlbGxpZ2liaWxpdHkgcmF0aW5ncyBmb3IgdGhpcyBtb2RlbAogIGRwbHlyOjpmaWx0ZXIoY29uZGl0aW9uICE9ICJsZXNzQ2xlYXIiKSAlPiUgIyBXZSB3b24ndCB1c2UgdGhlIGxlc3MgY2xlYXIgY29uZGl0aW9uIGluIHRoaXMgc3R1ZHkKICAKICAjIEhlcmUgd2UgcmVuYW1lIHNvbWUgdmFyaWFibGVzIGFuZCBjbGVhbiB1cCB0aGUgZmFjdG9ycwogIGRwbHlyOjpyZW5hbWUoSW50ID0gUmF0aW5nKSAlPiUKICBkcGx5cjo6bXV0YXRlKFNleCA9IGZhY3RvcihTZXgsIGxldmVscyA9IGMoIk0iLCAiRiIpKSwKICAgICAgICAgICAgICAgIGNvbmRpdGlvbiA9IGZhY3Rvcihjb25kaXRpb24sIGxldmVscyA9IGMoImNvbnYiLCAibW9yZUNsZWFyIikpKSAlPiUKICAKICAjIE5vdyB3ZSBtZXJnZSB0aGUgaW50ZWxsaWdpYmlsaXR5IHJhdGluZ3Mgd2l0aCB0aGUgc3BlYWtlckxpc3QsIHdoaWNoIGhhcyBpbmZvcm1hdGlvbiBhYm91dCBzZXZlcml0eSBsZXZlbC4KICBiYXNlOjptZXJnZSguLCBzcGVha2VyTGlzdCAlPiUKICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoU3R1ZHlJRCwgU2V2ZXJpdHkpKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgU2V2ZXJpdHkgPSBmYWN0b3IoCiAgICAgIFNldmVyaXR5LAogICAgICBsZXZlbHMgPSBjKCJIQyIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBsYWJlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICAgICkKICApICU+JQogIGRwbHlyOjpyZWxvY2F0ZShTZXZlcml0eSwgLmFmdGVyID0gR3JvdXApCgojIExldHMgdmlzdWFsaXplIHRoZSBvdXRjb21lIG1lYXN1cmUsIGludGVsbGlnaWJpbGl0eQpoaXN0KHBlcmNlcHR1YWxNZWFzdXJlcyRJbnQpCgojIEhlcmUsIHdlIHJlc2NhbGUgdGhlIG1lYXN1cmUgdG8gZml0IGEgYmV0YSBkaXN0cmlidGlvbgplcHNpbG9uIDwtIDFlLTUKZGF0YV9tb2RlbERhdGFfSW50IDwtIHBlcmNlcHR1YWxNZWFzdXJlcyAlPiUKICBkcGx5cjo6c2VsZWN0KFN0dWR5SUQsCiAgICAgICAgICAgICAgICBHcm91cCwKICAgICAgICAgICAgICAgIFNleCwKICAgICAgICAgICAgICAgIEFnZSwKICAgICAgICAgICAgICAgIFNldmVyaXR5LAogICAgICAgICAgICAgICAgY29uZGl0aW9uLAogICAgICAgICAgICAgICAgU2VudCwKICAgICAgICAgICAgICAgIHJlcCwKICAgICAgICAgICAgICAgIExpc3RlbmVySUQsCiAgICAgICAgICAgICAgICBJbnQpICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBJbnQgPSBJbnQgLyAxMDAsCiAgICAjIHRoZSBmb2xsb3dpbmcgbWFrZXMgc3VyZSB0aGF0IDAgYW5kIDEgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgYmV0YSBkaXN0cmlidXRpb24KICAgIEludCA9IEludCAqICgobnJvdyguKSAtIDEpICsgLjUpIC8gbnJvdyguKSwKICAgIEludCA9IEludCAqICgxIC0gMiAqIGVwc2lsb24pICsgZXBzaWxvbgogICkKCnBlcmZvcm1hbmNlOjpjaGVja19kaXN0cmlidXRpb24oZGF0YV9tb2RlbERhdGFfSW50JEludCkKCiMgVGFraW5nIG91dCB0aGUgdHJhc2gKcm0ocGVyY2VwdHVhbE1lYXN1cmVzLCBlcHNpbG9uKQpgYGAKCiMjIyBQcmlvcnMKRmlyc3QsIHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgbW9kZWwgcGFyYW1ldGVycwpgYGB7cn0KCm1vZGVsRm9ybXVsYV9JbnQgPC0KICBJbnQgfiBTZXZlcml0eSAqIGNvbmRpdGlvbiArCiAgKDEgfCBTdHVkeUlEIC8gU2VudCAvIHJlcCkgKyAjIEVhY2ggU3BlYWtlciAoU3R1ZHlJRCkgcmVhZCB0aHJlZSBzZW50ZW5jZXMgKFNlbnQpLCBmaXZlIHRpbWVzIGVhY2ggKHJlcCkKICAoMSB8IExpc3RlbmVySUQpCgpicm1zOjpnZXRfcHJpb3IoCiAgbW9kZWxGb3JtdWxhX0ludCwgCiAgZGF0YSA9IGRhdGFfbW9kZWxEYXRhX0ludCwgCiAgZmFtaWx5ID0gQmV0YSkKYGBgCk5vdyB3ZSBjYW4gc3BlY2lmeSB3ZWFrbHkgaW5mb3JtYXRpdmUgcHJpb3JzLgpgYGB7cn0KcHJpb3JfSW50IDwtIGMoCiAgcHJpb3Iobm9ybWFsKDAsIDEwKSwgY2xhc3MgPSBJbnRlcmNlcHQpLCAjIHN0YXJ0IHdpdGggbGFyZ2VyIHZhbHVlIC0gMTAKICBwcmlvcihub3JtYWwoMCwgMTApLCBjbGFzcyA9IGIpLAogIHByaW9yKGNhdWNoeSgwLCAxMCksIGNsYXNzID0gc2QpLCAjIHBhcGVyIG9uIHZhcmlhbmNlIHByaW9yczogaHR0cHM6Ly9wcm9qZWN0ZXVjbGlkLm9yZy9qb3VybmFscy9iYXllc2lhbi1hbmFseXNpcy92b2x1bWUtMS9pc3N1ZS0zL1ByaW9yLWRpc3RyaWJ1dGlvbnMtZm9yLXZhcmlhbmNlLXBhcmFtZXRlcnMtaW4taGllcmFyY2hpY2FsLW1vZGVscy1jb21tZW50LW9uLzEwLjEyMTQvMDYtQkExMTdBLmZ1bGwgLSBjaGVjayA5NSUgaW50ZXJ2YWwgZm9yIGNhdWNoeSAtIHZlcnkgbGFyZ2UgdXBwZXIgYm91bmQgMTAKICBwcmlvcihnYW1tYSgxLCAwLjUpLCBjbGFzcyA9IHBoaSkgIyBQaGkgPSAxLCBtdSA9IC41CikKYGBgCgojIyMgQnVpbGRpbmcgdGhlIG1vZGVsCmBgYHtyfQptb2RlbF9JbnQgPC0gYnJtczo6YnJtKAogIGZvcm11bGEgPSBtb2RlbEZvcm11bGFfSW50LAogIGRhdGEgPSBkYXRhX21vZGVsRGF0YV9JbnQsCiAgcHJpb3IgPSBwcmlvcl9JbnQsCiAgZmFtaWx5ID0gQmV0YSwKICBjaGFpbnMgPSA0LAogIGNvcmVzID0gNCwKICBpdGVyID0gNDAwMCwKICB3YXJtdXAgPSAxMDAwLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45NSksCiAgZmlsZSA9ICJNb2RlbHMvYnJtc19JbnQucmRzIiwKICBmaWxlX3JlZml0ID0gIm9uX2NoYW5nZSIKKQpgYGAKCiMjIyBNb2RlbCBTdW1tYXJ5CmBgYHtyfQojIFByb2JhYmlsaXR5IG9mIGRpcmVjdGlvbiAocGQpCnBkX0ludCA8LSBiYXllc3Rlc3RSOjpwX2RpcmVjdGlvbihtb2RlbF9JbnQpICU+JQogIGRwbHlyOjpyZW5hbWUodGVybSA9IFBhcmFtZXRlciwKICAgICAgICAgICAgICAgIGVmZmVjdCA9IEVmZmVjdHMsCiAgICAgICAgICAgICAgICBjb21wb25lbnQgPSBDb21wb25lbnQpICU+JQogIGRwbHlyOjptdXRhdGUoCiAgICBjb21wb25lbnQgPSBpZmVsc2UoY29tcG9uZW50ID09ICJjb25kaXRpb25hbCIsICJjb25kIiwgY29tcG9uZW50KSwKICAgIHRlcm0gPSBnc3ViKHBhdHRlcm4gPSAiYl8iLCByZXBsYWNlbWVudCA9ICIiLCB0ZXJtKSwKICAgIHRlcm0gPSBpZmVsc2UodGVybSA9PSAiSW50ZXJjZXB0IiwgIihJbnRlcmNlcHQpIiwgdGVybSkpCgojIE1vZGVsIHJlc3VsdHMKbW9kZWxTdW1tYXJ5X0ludCA8LSB0aWR5KG1vZGVsX0ludCkgJT4lCiAgZHBseXI6OnJlbmFtZShsXzk1X0NJID0gY29uZi5sb3csCiAgICAgICAgICAgICAgICB1Xzk1X0NJID0gY29uZi5oaWdoKSAlPiUKICBkcGx5cjo6bXV0YXRlKG9yZGVyID0gcm93X251bWJlcigpKSAlPiUKICBiYXNlOjptZXJnZSguLHBkX0ludCwgYWxsID0gVCkgJT4lCiAgZHBseXI6OmFycmFuZ2Uob3JkZXIpICU+JQogIGRwbHlyOjpzZWxlY3QoIW9yZGVyKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgZXN0aW1hdGVfbmF0U2NhbGUgPSBwbG9naXMoZXN0aW1hdGUpLAogICAgbF85NV9DSV9uYXRTY2FsZSA9IHBsb2dpcyhsXzk1X0NJKSwKICAgIHVfOTVfQ0lfbmF0U2NhbGUgPSBwbG9naXModV85NV9DSSksCiAgICByb2J1c3QgPSBjYXNlX3doZW4oCiAgICAgIGFzLmludGVnZXIoIShsXzk1X0NJIDw9IDAgJiB1Xzk1X0NJID4gMCkpID09IDEgJiBwZCA+IC45NSB+ICJyb2J1c3QiLAogICAgICBUUlVFIH4gIm5vdCByb2J1c3QiCiAgICApCiAgKQoKcm0ocGRfSW50KQpgYGAKIyMjIE1vZGVsIERpYWdub3N0aWNzCmBgYHtyfQojIEFzc2VzcyBjaGFpbiBtaXhpbmcKcGxvdF9jaGFpbk1peF9JbnQgPC0gYmFzZTo6cGxvdChtb2RlbF9JbnQsIGFzaz1GQUxTRSkKCiMgUG9zdGVyaW9yIHByZWRpY3RpdmUgY2hlY2sKcGxvdF9wcENoZWNrX0ludCA8LSBicm1zOjpwcF9jaGVjayhtb2RlbF9JbnQsIG5kcmF3cyA9IDEwMDApCgojIFBsb3QgY29uZGl0aW9uYWwgZWZmZWN0cwpwbG90X2NvbmRpdGlvbmFsRWZmZWN0c19JbnQgPC0gYmFzZTo6cGxvdChjb25kaXRpb25hbF9lZmZlY3RzKG1vZGVsX0ludCksIGFzayA9IEZBTFNFKQoKIyBJbnRlcnZhbCBFc3RpbWF0aW9ucwpkYXRhX3Bvc3Rlcmlvcl9JbnQgPC0gYXMubWF0cml4KG1vZGVsX0ludCkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgpwbG90X2ludGVydmFsRXN0X0ludCA8LSBtY21jX2FyZWFzKAogIGRhdGFfcG9zdGVyaW9yX0ludCwKICBwYXJzID0gZml4ZWRfZWZmZWN0cyA8LSBkYXRhX3Bvc3Rlcmlvcl9JbnQgJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJiXyIpKSAlPiUKICAgIGNvbG5hbWVzKCksCiAgIyBhcmJpdHJhcnkgdGhyZXNob2xkIGZvciBzaGFkaW5nIHByb2JhYmlsaXR5IG1hc3MKICBwcm9iID0gMC45NQopIAoKYGBgCgojIyMgVmlzdWFsaXphdGlvbnMKYGBge3J9CgojIEdlbmVyYXRlIGV4cGVjdGVkIHByZWRpY3Rpb25zIGZyb20gdGhlIHBvc3RlcmlvCmRhdGFfcG9zdGVyaW9yX0ludCA8LSBtb2RlbF9JbnQgJT4lCiAgdGlkeWJheWVzOjplcHJlZF9kcmF3cygKICAgIG5ld2RhdGEgPSB0aWR5cjo6ZXhwYW5kX2dyaWQoCiAgICAgIFNldmVyaXR5ID0gYygiQ29udHJvbCIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBjb25kaXRpb24gPSBjKCJjb252IiwgIm1vcmVDbGVhciIpCiAgICApLAogICAgcmVfZm9ybXVsYSA9IE5BCiAgKSAlPiUKICBkcGx5cjo6bXV0YXRlKFNldmVyaXR5ID0gZmFjdG9yKAogICAgU2V2ZXJpdHksCiAgICBsZXZlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICApLAogIGNvbmRpdGlvbiA9IGZhY3Rvcihjb25kaXRpb24sCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImNvbnYiLCJtb3JlQ2xlYXIiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiY29udmVyc2F0aW9uYWwiLCAiY2xlYXIiKSkpCgpwbG90X2dyYW5kTWVhbl9JbnQgPC0gZ2dwbG90KGRhdGFfcG9zdGVyaW9yX0ludCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSAuZXByZWQsIHkgPSBTZXZlcml0eSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjb25kaXRpb24pKSArCiAgc3RhdF9oYWxmZXllKCkgKwogIGdnb2thYmVpdG86OnNjYWxlX2ZpbGxfb2thYmVfaXRvKCkgKwogIGxhYnMoeCA9ICJQcmVkaWN0ZWQgaW50ZWxsaWdpYmlsaXR5IHJhdGluZyIsIHkgPSBOVUxMLAogICAgICAgZmlsbCA9ICJDb25kaXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiUG9zdGVyaW9yIHByZWRpY3Rpb25zIikgKwogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMSkpICsKICB0aGVtZV9jbGVhbigpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmVwc2lsb24gPC0gMWUtNQpkYXRhX21lX0ludCA8LSBtb2RlbF9JbnQgJT4lCiAgZW1tZWFuczo6ZW1tZWFucyggfiBjb25kaXRpb24gfCBTZXZlcml0eSwKICAgICAgICAgICAgICAgICAgICAjYXQgPSBsaXN0KFNldmVyaXR5ID0gIlByb2ZvdW5kIiksCiAgICAgICAgICAgICAgICAgICAgZXByZWQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSwKICAgICAgICAgICAgICAgICAgICApICU+JQogIGVtbWVhbnM6OmNvbnRyYXN0KG1ldGhvZCA9ICJyZXZwYWlyd2lzZSIpICU+JQogIGdhdGhlcl9lbW1lYW5zX2RyYXdzKCkgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIC52YWx1ZSA9ICgudmFsdWUgLSBlcHNpbG9uKSAvICgxIC0gMiAqIGVwc2lsb24pLAogICAgIyBTdGVwIDEgJiAyOiBSZXZlcnNlIHRoZSBvZmZzZXQgYW5kIHNjYWxpbmcKICAgIC52YWx1ZSA9IC52YWx1ZSAqIG5yb3coLikgLyAoKG5yb3coLikgLSAxKSArIC41KQogICkKCgpwbG90X2FtZV9JbnQgPC0gZ2dwbG90KGRhdGFfbWVfSW50LCBhZXMoeCA9IC52YWx1ZSwgeSA9IFNldmVyaXR5KSkgKwogIHN0YXRfaGFsZmV5ZShmaWxsID0gZ2dva2FiZWl0bzo6cGFsZXR0ZV9va2FiZV9pdG8ob3JkZXIgPSA3KSkgKwogIGxhYnMoeCA9ICJBdmVyYWdlIG1hcmdpbmFsIGVmZmVjdCBvZiBjb25kaXRpb24iLAogICAgICAgeSA9IE5VTEwsCiAgICAgICBzdWJ0aXRsZSA9ICJDb25kaXRpb24gZWZmZWN0IChjbGVhciAtIGNvbnZlcnNhdGlvbmFsKSIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHRoZW1lX2NsZWFuKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKIyBDb21iaW5lZCBwbG90CnBsb3RfSW50IDwtIChwbG90X2dyYW5kTWVhbl9JbnQgfCBwbG90X2FtZV9JbnQpICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiSW50ZWxsaWdpYmlsaXR5IiwKICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiSW50ZWxsaWdpYmlsaXR5IHJhdGluZ3MgYWNyb3NzIGdyb3VwL3NldmVyaXR5IGFuZCBzcGVha2luZyBjb25kaXRpb25zLiIsCiAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWVfY2xlYW4oKSkKZ2dzYXZlKAogIHBsb3QgPSBwbG90X0ludCwKICBmaWxlbmFtZSA9ICJQbG90cy9wbG90X0ludC5wbmciLAogIGhlaWdodCA9IDYsCiAgd2lkdGggPSA4LAogIHVuaXQgPSAiaW4iLAogIHNjYWxlID0gMSwKICBiZyA9ICJ3aGl0ZSIKKQpgYGAKCiMjIEFydGljdWxhdG9yeSBQcmVjaXNpb24KQXJ0aWN1bGF0b3J5IHByZWNpc2lvbiB3YXMgY29sbGVjdGVkIGluIHRoZSBzYW1lIHdheSBhcyBpbnRlbGxpZ2liaWxpdHkgcmF0aW5ncy4gVGhleSB3ZXJlIGNvbGxlY3RlZCB0aHJvdWdoIHJhdGluZ3Mgb2J0YWluZWQgdGhyb3VnaCBhIGxpc3RlbmVyIHN1cnZleS4gVGhleSB3b3VsZCBsaXN0ZW4gdG8gYSBzcGVha2VyLCBhbmQgdGhlbiByYXRlIGhvdyBwcmVjaXNlIHRoZSBzcGVha2VyIHdhcyB1c2luZyBhIGhvcml6b250YWxseSBvcmllbnRlZCB2aXN1YWwgYW5hbG9nIHNjYWxlLiBUaGUgbGVmdCBlbmQgb2YgdGhlIHNjYWxlIHdhcyBsYWJlbGVkICJpbXByZWNpc2Ugb3IgbXVtYmxlZCIgYW5kIGNvcnJlc3BvbmRlZCB0byBhIHZhbHVlIG9mIDAuIFRoZSByaWdodCBlbmQgb2YgdGhlIHNjYWxlIHdhcyBsYWJlbGVkICJwcmVjaXNlIG9yIGNsZWFyIiBhbmQgY29ycmVzcG9uZGVkIHRvIGEgdmFsdWUgb2YgMTAwLgoKV2hpbGUgYW55IHZhbHVlIGJldHdlZW4gMCBhbmQgMTAwIGNvdWxkIGJlIHNlbGVjdGVkLCBsaXN0ZW5lcnMgdGVuZGVkIHRvIHJhdGUgb24gdGhlIGV4dHJlbWUgZW5kcywgcmVzdWx0aW5nIGluIGEgYmV0YSBkaXN0cmlidXRpb24uIFRoZXJlZm9yZSwgZm9yIHRoaXMgbW9kZWwsIHdlIHVzZWQgYSBiZXRhIGZhbWlseSBmb3Igb3VyIG1vZGVsLiBCdXQgZmlyc3QsIHdlIHJlc2NhbGVkIHRoZSBwcmVjaXNpb24gcmF0aW5ncyB0byBmYWxsIGJldHdlZW4gMCBhbmQgMSwgZXhjbHVkaW5nIHRoZSBlbmRwb2ludCB2YWx1ZXMgb2YgMCBhbmQgMS4KCiMjIyBMb2FkaW5nIHRoZSBkYXRhCmBgYHtyfQpwZXJjZXB0dWFsTWVhc3VyZXMgPC0gcmlvOjppbXBvcnQoZmlsZSA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQXVzdGluUlRob21wc29uL211bHRpZG9tYWluLXZvd2VsQXJ0aWMtUEQvbWFpbi9EYXRhL1ByZXBwZWREYXRhL0xpc3RlbmVyRGF0YS9MaXN0ZW5lclJhdGluZ3NfYWxsUmF0aW5ncy5jc3YiKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFWMSkgJT4lCiAgZHBseXI6OmZpbHRlcihyYXRpbmdUeXBlID09ICJBUCIpICU+JSAjIFdlIG9ubHkgd2FudCB0aGUgaW50ZWxsaWdpYmlsaXR5IHJhdGluZ3MgZm9yIHRoaXMgbW9kZWwKICBkcGx5cjo6ZmlsdGVyKGNvbmRpdGlvbiAhPSAibGVzc0NsZWFyIikgJT4lICMgV2Ugd29uJ3QgdXNlIHRoZSBsZXNzIGNsZWFyIGNvbmRpdGlvbiBpbiB0aGlzIHN0dWR5CiAgCiAgIyBIZXJlIHdlIHJlbmFtZSBzb21lIHZhcmlhYmxlcyBhbmQgY2xlYW4gdXAgdGhlIGZhY3RvcnMKICBkcGx5cjo6cmVuYW1lKEFQID0gUmF0aW5nKSAlPiUKICBkcGx5cjo6bXV0YXRlKFNleCA9IGZhY3RvcihTZXgsIGxldmVscyA9IGMoIk0iLCAiRiIpKSwKICAgICAgICAgICAgICAgIGNvbmRpdGlvbiA9IGZhY3Rvcihjb25kaXRpb24sIGxldmVscyA9IGMoImNvbnYiLCAibW9yZUNsZWFyIikpKSAlPiUKICAKICAjIE5vdyB3ZSBtZXJnZSB0aGUgaW50ZWxsaWdpYmlsaXR5IHJhdGluZ3Mgd2l0aCB0aGUgc3BlYWtlckxpc3QsIHdoaWNoIGhhcyBpbmZvcm1hdGlvbiBhYm91dCBzZXZlcml0eSBsZXZlbC4KICBiYXNlOjptZXJnZSguLCBzcGVha2VyTGlzdCAlPiUKICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoU3R1ZHlJRCwgU2V2ZXJpdHkpKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgU2V2ZXJpdHkgPSBmYWN0b3IoCiAgICAgIFNldmVyaXR5LAogICAgICBsZXZlbHMgPSBjKCJIQyIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBsYWJlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICAgICkKICApICU+JQogIGRwbHlyOjpyZWxvY2F0ZShTZXZlcml0eSwgLmFmdGVyID0gR3JvdXApCgoKIyBMZXRzIHZpc3VhbGl6ZSB0aGUgb3V0Y29tZSBtZWFzdXJlLCBpbnRlbGxpZ2liaWxpdHkKaGlzdChwZXJjZXB0dWFsTWVhc3VyZXMkQVApCgojIEhlcmUsIHdlIHJlc2NhbGUgdGhlIG1lYXN1cmUgdG8gZml0IGEgYmV0YSBkaXN0cmlidGlvbgplcHNpbG9uIDwtIDFlLTUKZGF0YV9tb2RlbERhdGFfQVAgPC0gcGVyY2VwdHVhbE1lYXN1cmVzICU+JQogIGRwbHlyOjpzZWxlY3QoU3R1ZHlJRCwKICAgICAgICAgICAgICAgIEdyb3VwLAogICAgICAgICAgICAgICAgU2V4LAogICAgICAgICAgICAgICAgQWdlLAogICAgICAgICAgICAgICAgU2V2ZXJpdHksCiAgICAgICAgICAgICAgICBjb25kaXRpb24sCiAgICAgICAgICAgICAgICBTZW50LAogICAgICAgICAgICAgICAgcmVwLAogICAgICAgICAgICAgICAgTGlzdGVuZXJJRCwKICAgICAgICAgICAgICAgIEFQKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgQVAgPSBBUCAvIDEwMCwKICAgIEFQID0gQVAgKiAoKG5yb3coLikgLSAxKSArIC41KSAvIG5yb3coLiksCiAgICBBUCA9IEFQICogKDEgLSAyICogZXBzaWxvbikgKyBlcHNpbG9uCiAgKSAjIHRoaXMgbWFrZXMgc3VyZSB0aGF0IDAgYW5kIDEgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgYmV0YSBkaXN0cmlidXRpb24KCnBlcmZvcm1hbmNlOjpjaGVja19kaXN0cmlidXRpb24oZGF0YV9tb2RlbERhdGFfQVAkQVApCgojIFRha2luZyBvdXQgdGhlIHRyYXNoCnJtKHBlcmNlcHR1YWxNZWFzdXJlcywgZXBzaWxvbikKYGBgCgojIyMgUHJpb3JzCkZpcnN0LCB3ZSBuZWVkIHRvIGZpZ3VyZSBvdXQgdGhlIG1vZGVsIHBhcmFtZXRlcnMKYGBge3J9Cm1vZGVsRm9ybXVsYV9BUCA8LSAKICBBUCB+IFNldmVyaXR5KmNvbmRpdGlvbiArIAogICAgKDEgfCBTdHVkeUlEL1NlbnQvcmVwKSArICMgRWFjaCBTcGVha2VyIChTdHVkeUlEKSByZWFkIHRocmVlIHNlbnRlbmNlcyAoU2VudCksIGZpdmUgdGltZXMgZWFjaCAocmVwKQogICAgKDEgfCBMaXN0ZW5lcklEKQoKYnJtczo6Z2V0X3ByaW9yKAogIG1vZGVsRm9ybXVsYV9BUCwKICBkYXRhID0gZGF0YV9tb2RlbERhdGFfQVAsCiAgZmFtaWx5ID0gQmV0YQopCmBgYAoKTm93IHdlIGNhbiBzcGVjaWZ5IHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMuCmBgYHtyfQpwcmlvcl9BUCA8LSBjKAogIHByaW9yKG5vcm1hbCgwLCAxMCksIGNsYXNzID0gSW50ZXJjZXB0KSwKICBwcmlvcihub3JtYWwoMCwgMTApLCBjbGFzcyA9IGIpLAogIHByaW9yKGNhdWNoeSgwLCAxMCksIGNsYXNzID0gc2QpLAogIHByaW9yKGdhbW1hKDEsIDAuNSksIGNsYXNzID0gcGhpKSAjIFBoaSA9IDEsIG11ID0gLjUKKQpgYGAKCiMjIyBCdWlsZGluZyB0aGUgbW9kZWwKYGBge3J9Cm1vZGVsX0FQIDwtIGJybXM6OmJybSgKICBmb3JtdWxhID0gbW9kZWxGb3JtdWxhX0FQLAogIGRhdGEgPSBkYXRhX21vZGVsRGF0YV9BUCwKICBwcmlvciA9IHByaW9yX0FQLAogIGZhbWlseSA9IEJldGEsCiAgY2hhaW5zID0gNCwKICBjb3JlcyA9IDQsCiAgaXRlciA9IDQwMDAsCiAgd2FybXVwID0gMTAwMCwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOTUpLAogIGZpbGUgPSAiTW9kZWxzL2JybXNfQVAucmRzIiwKICBmaWxlX3JlZml0ID0gIm9uX2NoYW5nZSIKKQpgYGAKCiMjIyBNb2RlbCBTdW1tYXJ5CmBgYHtyfQojIFByb2JhYmlsaXR5IG9mIGRpcmVjdGlvbiAocGQpCnBkX0FQIDwtIGJheWVzdGVzdFI6OnBfZGlyZWN0aW9uKG1vZGVsX0FQKSAlPiUKICBkcGx5cjo6cmVuYW1lKHRlcm0gPSBQYXJhbWV0ZXIsCiAgICAgICAgICAgICAgICBlZmZlY3QgPSBFZmZlY3RzLAogICAgICAgICAgICAgICAgY29tcG9uZW50ID0gQ29tcG9uZW50KSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgY29tcG9uZW50ID0gaWZlbHNlKGNvbXBvbmVudCA9PSAiY29uZGl0aW9uYWwiLCAiY29uZCIsIGNvbXBvbmVudCksCiAgICB0ZXJtID0gZ3N1YihwYXR0ZXJuID0gImJfIiwgcmVwbGFjZW1lbnQgPSAiIiwgdGVybSksCiAgICB0ZXJtID0gaWZlbHNlKHRlcm0gPT0gIkludGVyY2VwdCIsICIoSW50ZXJjZXB0KSIsIHRlcm0pKQoKIyBNb2RlbCByZXN1bHRzCm1vZGVsU3VtbWFyeV9BUCA8LSB0aWR5KG1vZGVsX0FQKSAlPiUKICBkcGx5cjo6cmVuYW1lKGxfOTVfQ0kgPSBjb25mLmxvdywKICAgICAgICAgICAgICAgIHVfOTVfQ0kgPSBjb25mLmhpZ2gpICU+JQogIGRwbHlyOjptdXRhdGUob3JkZXIgPSByb3dfbnVtYmVyKCkpICU+JQogIGJhc2U6Om1lcmdlKC4scGRfQVAsIGFsbCA9IFQpICU+JQogIGRwbHlyOjphcnJhbmdlKG9yZGVyKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFvcmRlcikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIHJvYnVzdCA9IGNhc2Vfd2hlbigKICAgICAgYXMuaW50ZWdlcighKGxfOTVfQ0kgPD0gMCAmIHVfOTVfQ0kgPiAwKSkgPT0gMSAmIHBkID4gLjk1IH4gInJvYnVzdCIsCiAgICAgIFRSVUUgfiAibm90IHJvYnVzdCIKICAgICkKICApCgpybShwZF9BUCkKYGBgCiMjIyBNb2RlbCBEaWFnbm9zdGljcwpgYGB7cn0KIyBBc3Nlc3MgY2hhaW4gbWl4aW5nCnBsb3RfY2hhaW5NaXhfQVAgPC0gYmFzZTo6cGxvdChtb2RlbF9BUCwgYXNrPUZBTFNFKQoKIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVjawpwbG90X3BwQ2hlY2tfQVAgPC0gYnJtczo6cHBfY2hlY2sobW9kZWxfQVAsIG5kcmF3cyA9IDEwMDApCgojIFBsb3QgY29uZGl0aW9uYWwgZWZmZWN0cwpwbG90X2NvbmRpdGlvbmFsRWZmZWN0c19BUCA8LSBiYXNlOjpwbG90KGNvbmRpdGlvbmFsX2VmZmVjdHMobW9kZWxfQVApLCBhc2sgPSBGQUxTRSkKCiMgQVBlcnZhbCBFc3RpbWF0aW9ucwpkYXRhX3Bvc3Rlcmlvcl9BUCA8LSBhcy5tYXRyaXgobW9kZWxfQVApICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKcGxvdF9pbnRlcnZhbEVzdF9BUCA8LSBtY21jX2FyZWFzKAogIGRhdGFfcG9zdGVyaW9yX0FQLAogIHBhcnMgPSBmaXhlZF9lZmZlY3RzIDwtIGRhdGFfcG9zdGVyaW9yX0FQICU+JQogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiYl8iKSkgJT4lCiAgICBjb2xuYW1lcygpLAogICMgYXJiaXRyYXJ5IHRocmVzaG9sZCBmb3Igc2hhZGluZyBwcm9iYWJpbGl0eSBtYXNzCiAgcHJvYiA9IDAuOTUKKSAKCmBgYAoKIyMjIFZpc3VhbGl6YXRpb25zCmBgYHtyfQoKIyBHZW5lcmF0ZSBleHBlY3RlZCBwcmVkaWN0aW9ucyBmcm9tIHRoZSBwb3N0ZXJpbwpkYXRhX3Bvc3Rlcmlvcl9BUCA8LSBtb2RlbF9BUCAlPiUKICB0aWR5YmF5ZXM6OmVwcmVkX2RyYXdzKAogICAgbmV3ZGF0YSA9IHRpZHlyOjpleHBhbmRfZ3JpZCgKICAgICAgU2V2ZXJpdHkgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIiksCiAgICAgIGNvbmRpdGlvbiA9IGMoImNvbnYiLCAibW9yZUNsZWFyIikKICAgICksCiAgICByZV9mb3JtdWxhID0gTkEKICApICU+JQogIGRwbHlyOjptdXRhdGUoU2V2ZXJpdHkgPSBmYWN0b3IoCiAgICBTZXZlcml0eSwKICAgIGxldmVscyA9IGMoIkNvbnRyb2wiLCAiTWlsZCIsICJNb2RlcmF0ZSIsICJTZXZlcmUiLCAiUHJvZm91bmQiKQogICksCiAgY29uZGl0aW9uID0gZmFjdG9yKGNvbmRpdGlvbiwKICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiY29udiIsIm1vcmVDbGVhciIpLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJjb252ZXJzYXRpb25hbCIsICJjbGVhciIpKSkKCnBsb3RfZ3JhbmRNZWFuX0FQIDwtIGdncGxvdChkYXRhX3Bvc3Rlcmlvcl9BUCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSAuZXByZWQsIHkgPSBTZXZlcml0eSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjb25kaXRpb24pKSArCiAgc3RhdF9oYWxmZXllKCkgKwogIGdnb2thYmVpdG86OnNjYWxlX2ZpbGxfb2thYmVfaXRvKCkgKwogIGxhYnMoeCA9ICJQcmVkaWN0ZWQgYXJ0aWN1bGF0b3J5IHByZWNpc2lvbiByYXRpbmciLCB5ID0gTlVMTCwKICAgICAgIGZpbGwgPSAiQ29uZGl0aW9uIiwKICAgICAgIHN1YnRpdGxlID0gIlBvc3RlcmlvciBwcmVkaWN0aW9ucyIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDEpKSArCiAgdGhlbWVfY2xlYW4oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgplcHNpbG9uIDwtIDFlLTUKZGF0YV9tZV9BUCA8LSBtb2RlbF9BUCAlPiUKICBlbW1lYW5zOjplbW1lYW5zKCB+IGNvbmRpdGlvbiB8IFNldmVyaXR5LAogICAgICAgICAgICAgICAgICAgICNhdCA9IGxpc3QoU2V2ZXJpdHkgPSAiUHJvZm91bmQiKSwKICAgICAgICAgICAgICAgICAgICBlcHJlZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BLAogICAgICAgICAgICAgICAgICAgICkgJT4lCiAgZW1tZWFuczo6Y29udHJhc3QobWV0aG9kID0gInJldnBhaXJ3aXNlIikgJT4lCiAgZ2F0aGVyX2VtbWVhbnNfZHJhd3MoKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgLnZhbHVlID0gKC52YWx1ZSAtIGVwc2lsb24pIC8gKDEgLSAyICogZXBzaWxvbiksCiAgICAjIFN0ZXAgMSAmIDI6IFJldmVyc2UgdGhlIG9mZnNldCBhbmQgc2NhbGluZwogICAgLnZhbHVlID0gLnZhbHVlICogbnJvdyguKSAvICgobnJvdyguKSAtIDEpICsgLjUpCiAgKQoKCnBsb3RfYW1lX0FQIDwtIGdncGxvdChkYXRhX21lX0FQLCBhZXMoeCA9IC52YWx1ZSwgeSA9IFNldmVyaXR5KSkgKwogIHN0YXRfaGFsZmV5ZShmaWxsID0gZ2dva2FiZWl0bzo6cGFsZXR0ZV9va2FiZV9pdG8ob3JkZXIgPSA3KSkgKwogIGxhYnMoeCA9ICJBdmVyYWdlIG1hcmdpbmFsIGVmZmVjdCBvZiBjb25kaXRpb24iLAogICAgICAgeSA9IE5VTEwsCiAgICAgICBzdWJ0aXRsZSA9ICJDb25kaXRpb24gZWZmZWN0IChjbGVhciAtIGNvbnZlcnNhdGlvbmFsKSIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHRoZW1lX2NsZWFuKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKIyBDb21iaW5lZCBwbG90CnBsb3RfQVAgPC0gKHBsb3RfZ3JhbmRNZWFuX0FQIHwgcGxvdF9hbWVfQVApICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiQXJ0aWN1bGF0b3J5IFByZWNpc2lvbiIsCiAgICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIlByZWRpY3RlZCBhcnRpY3VsYXRvcnkgcHJlY2lzaW9uIHJhdGluZ3MgYWNyb3NzIGdyb3VwL3NldmVyaXR5IGFuZCBzcGVha2luZyBjb25kaXRpb25zLiIsCiAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWVfY2xlYW4oKSkKZ2dzYXZlKAogIHBsb3QgPSBwbG90X0FQLAogIGZpbGVuYW1lID0gIlBsb3RzL3Bsb3RfQVAucG5nIiwKICBoZWlnaHQgPSA2LAogIHdpZHRoID0gOCwKICB1bml0ID0gImluIiwKICBzY2FsZSA9IDEsCiAgYmcgPSAid2hpdGUiCikKYGBgCgojIyBhVlNBCkFjb3VzdGljIFZvd2VsIFNwYWNlIEFyZWEgKGFWU0EpIGlzIGFuIGFjb3VzdGljIG1lYXN1cmUgb2YgYXJ0aWN1bGF0b3J5IHdvcmtpbmcgc3BhY2UuIFRoZXJlIGFyZSBrbm93biBzZXggZGlmZmVyZW5jZXMgd2hlbiBhVlNBIGlzIG1lYXN1cmVkIGluIEh6LiBUaGVyZWZvcmUsIHdlIHdpbGwgbWVhc3VyZSBpdCBpbiBCYXJrIHRvIHRyeSB0byByZWR1Y2UgdGhlIHNleCBlZmZlY3RzLgoKVGhlIGJhcmsgdHJhbnNmb3JtZWQgYVZTQSBtZWFzdXJlIHJhbmdlcyBmcm9tIC44IC0gMTggQmFyay4gU28gaXQgaXMgYSBtZWFzdXJlIGJvdW5kIGJ5IDAsIHdpdGggbm8gbmVnYXRpdmUgdmFsdWVzLiBGb3IgdGhpcyByZWFzb24sIHdlIHdpbGwgdXNlIGEgbG9nbm9ybWFsIGZhbWlseS4KIyMjIExvYWRpbmcgdGhlIGRhdGEKYGBge3J9CnZzYU1lYXN1cmVzIDwtIHJpbzo6aW1wb3J0KGZpbGUgPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0F1c3RpblJUaG9tcHNvbi9tdWx0aWRvbWFpbi12b3dlbEFydGljLVBEL21haW4vRGF0YS9QcmVwcGVkRGF0YS9Db2xsYXRlZERhdGEvVGFyZ2V0TWVhc3VyZXNfdnNhTWVhc3VyZXMuY3N2IikgJT4lCiAgZHBseXI6OmZpbHRlcihjb25kaXRpb24gIT0gImxlc3NDbGVhciIpICU+JSAjIFdlIHdvbid0IHVzZSB0aGUgbGVzcyBjbGVhciBjb25kaXRpb24gaW4gdGhpcyBzdHVkeQogIAogICMgSGVyZSB3ZSByZW5hbWUgc29tZSB2YXJpYWJsZXMgYW5kIGNsZWFuIHVwIHRoZSBmYWN0b3JzCiAgZHBseXI6Om11dGF0ZShTZXggPSBmYWN0b3IoU2V4LCBsZXZlbHMgPSBjKCJNIiwgIkYiKSksCiAgICAgICAgICAgICAgICBjb25kaXRpb24gPSBmYWN0b3IoY29uZGl0aW9uLCBsZXZlbHMgPSBjKCJjb252IiwgIm1vcmVDbGVhciIpKSkgJT4lCiAgCiAgIyBOb3cgd2UgbWVyZ2UgdGhlIGRhdGEgd2l0aCB0aGUgc3BlYWtlckxpc3QsIHdoaWNoIGhhcyBpbmZvcm1hdGlvbiBhYm91dCBzZXZlcml0eSBsZXZlbC4KICBiYXNlOjptZXJnZSguLCBzcGVha2VyTGlzdCAlPiUKICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoU3R1ZHlJRCwgU2V2ZXJpdHkpKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgU2V2ZXJpdHkgPSBmYWN0b3IoCiAgICAgIFNldmVyaXR5LAogICAgICBsZXZlbHMgPSBjKCJIQyIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBsYWJlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICAgICkKICApCgojIExldHMgdmlzdWFsaXplIHRoZSBvdXRjb21lIG1lYXN1cmUsIGFWU0FfYmFyawpoaXN0KHZzYU1lYXN1cmVzJGFWU0FfYmFyaykKCmRhdGFfbW9kZWxEYXRhX2FWU0EgPC0gdnNhTWVhc3VyZXMKcGVyZm9ybWFuY2U6OmNoZWNrX2Rpc3RyaWJ1dGlvbihkYXRhX21vZGVsRGF0YV9hVlNBJGFWU0FfYmFyaykKCiMgVGFraW5nIG91dCB0aGUgdHJhc2gKcm0odnNhTWVhc3VyZXMpCmBgYAoKIyMjIFByaW9ycwpGaXJzdCwgd2UgbmVlZCB0byBmaWd1cmUgb3V0IHRoZSBtb2RlbCBwYXJhbWV0ZXJzCmBgYHtyfQptb2RlbEZvcm11bGFfYVZTQSA8LSAKICBhVlNBX2JhcmsgfiAKICBTZXZlcml0eSAqIGNvbmRpdGlvbiArCiAgKDEgfCBTdHVkeUlEKSAjIEhlcmUsIHdlIG9ubHkgaGF2ZSBvbmUgYVZTQSB2YWx1ZSBwZXIgc3BlYWtlciBhbmQgY29uZGl0aW9uCgpicm1zOjpnZXRfcHJpb3IoCiAgZm9ybXVsYSA9IG1vZGVsRm9ybXVsYV9hVlNBLAogIGRhdGEgPSBkYXRhX21vZGVsRGF0YV9hVlNBLAogIGZhbWlseSA9IGxvZ25vcm1hbCgpKQpgYGAKTm93IHdlIGNhbiBzcGVjaWZ5IHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMuCmBgYHtyfQojIHNwZWNpZnkgcHJpb3JzIGluIGxvZyBzcGFjZQpwcmlvcnNfYVZTQSA8LSBjKAogIHByaW9yKG5vcm1hbCgwLCAxMCksIGNsYXNzID0gSW50ZXJjZXB0KSwKICBwcmlvcihub3JtYWwoMCwgMTApLCBjbGFzcyA9IGIpLAogIHByaW9yKGNhdWNoeSgwLCAxMCksIGNsYXNzID0gc2QpLAogIHByaW9yKGNhdWNoeSgwLCAxMCksIGNsYXNzID0gc2lnbWEpCikKYGBgCgojIyMgQnVpbGRpbmcgdGhlIG1vZGVsCmBgYHtyfQoKbW9kZWxfYVZTQSA8LSBicm1zOjpicm0oCiAgZm9ybXVsYSA9IG1vZGVsRm9ybXVsYV9hVlNBLAogIGRhdGEgPSBkYXRhX21vZGVsRGF0YV9hVlNBLAogIGZhbWlseSA9IGxvZ25vcm1hbCgpLAogIHByaW9yID0gcHJpb3JzX2FWU0EsCiAgY2hhaW5zID0gNCwKICBjb3JlcyA9IDQsCiAgaXRlciA9IDQwMDAsCiAgd2FybXVwID0gMTAwMCwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOTUpLAogIGZpbGUgPSAiTW9kZWxzL2JybXNfYVZTQS5yZHMiLAogIGZpbGVfcmVmaXQgPSAib25fY2hhbmdlIgopCmBgYAoKIyMjIE1vZGVsIFN1bW1hcnkKYGBge3J9CiMgUHJvYmFiaWxpdHkgb2YgZGlyZWN0aW9uIChwZCkKcGRfYVZTQSA8LSBiYXllc3Rlc3RSOjpwX2RpcmVjdGlvbihtb2RlbF9hVlNBKSAlPiUKICBkcGx5cjo6cmVuYW1lKHRlcm0gPSBQYXJhbWV0ZXIsCiAgICAgICAgICAgICAgICBlZmZlY3QgPSBFZmZlY3RzLAogICAgICAgICAgICAgICAgY29tcG9uZW50ID0gQ29tcG9uZW50KSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgY29tcG9uZW50ID0gaWZlbHNlKGNvbXBvbmVudCA9PSAiY29uZGl0aW9uYWwiLCAiY29uZCIsIGNvbXBvbmVudCksCiAgICB0ZXJtID0gZ3N1YihwYXR0ZXJuID0gImJfIiwgcmVwbGFjZW1lbnQgPSAiIiwgdGVybSksCiAgICB0ZXJtID0gaWZlbHNlKHRlcm0gPT0gIkludGVyY2VwdCIsICIoSW50ZXJjZXB0KSIsIHRlcm0pKQoKIyBNb2RlbCByZXN1bHRzCm1vZGVsU3VtbWFyeV9hVlNBIDwtIHRpZHkobW9kZWxfYVZTQSkgJT4lCiAgZHBseXI6OnJlbmFtZShsXzk1X0NJID0gY29uZi5sb3csCiAgICAgICAgICAgICAgICB1Xzk1X0NJID0gY29uZi5oaWdoKSAlPiUKICBkcGx5cjo6bXV0YXRlKG9yZGVyID0gcm93X251bWJlcigpKSAlPiUKICBiYXNlOjptZXJnZSguLHBkX2FWU0EsIGFsbCA9IFQpICU+JQogIGRwbHlyOjphcnJhbmdlKG9yZGVyKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFvcmRlcikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIHJvYnVzdCA9IGNhc2Vfd2hlbigKICAgICAgYXMuaW50ZWdlcighKGxfOTVfQ0kgPD0gMCAmIHVfOTVfQ0kgPiAwKSkgPT0gMSAmIHBkID4gLjk1IH4gInJvYnVzdCIsCiAgICAgIFRSVUUgfiAibm90IHJvYnVzdCIKICAgICkKICApCgpybShwZF9hVlNBKQpgYGAKIyMjIE1vZGVsIERpYWdub3N0aWNzCmBgYHtyfQojIEFzc2VzcyBjaGFpbiBtaXhpbmcKcGxvdF9jaGFpbk1peF9hVlNBIDwtIGJhc2U6OnBsb3QobW9kZWxfYVZTQSwgYXNrPUZBTFNFKQoKIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVjawpwbG90X3BwQ2hlY2tfYVZTQSA8LSBicm1zOjpwcF9jaGVjayhtb2RlbF9hVlNBLCBuZHJhd3MgPSAxMDAwKQoKIyBQbG90IGNvbmRpdGlvbmFsIGVmZmVjdHMKcGxvdF9jb25kaXRpb25hbEVmZmVjdHNfYVZTQSA8LSBiYXNlOjpwbG90KGNvbmRpdGlvbmFsX2VmZmVjdHMobW9kZWxfYVZTQSksIGFzayA9IEZBTFNFKQoKIyBhVlNBZXJ2YWwgRXN0aW1hdGlvbnMKZGF0YV9wb3N0ZXJpb3JfYVZTQSA8LSBhcy5tYXRyaXgobW9kZWxfYVZTQSkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgpwbG90X2ludGVydmFsRXN0X2FWU0EgPC0gbWNtY19hcmVhcygKICBkYXRhX3Bvc3Rlcmlvcl9hVlNBLAogIHBhcnMgPSBmaXhlZF9lZmZlY3RzIDwtIGRhdGFfcG9zdGVyaW9yX2FWU0EgJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KHN0YXJ0c193aXRoKCJiXyIpKSAlPiUKICAgIGNvbG5hbWVzKCksCiAgIyBhcmJpdHJhcnkgdGhyZXNob2xkIGZvciBzaGFkaW5nIHByb2JhYmlsaXR5IG1hc3MKICBwcm9iID0gMC45NQopIAoKYGBgCgojIyMgVmlzdWFsaXphdGlvbnMKYGBge3J9CgojIEdlbmVyYXRlIGV4cGVjdGVkIHByZWRpY3Rpb25zIGZyb20gdGhlIHBvc3RlcmlvcgpkYXRhX3Bvc3Rlcmlvcl9hVlNBIDwtIG1vZGVsX2FWU0EgJT4lCiAgdGlkeWJheWVzOjplcHJlZF9kcmF3cygKICAgIG5ld2RhdGEgPSB0aWR5cjo6ZXhwYW5kX2dyaWQoCiAgICAgIFNldmVyaXR5ID0gYygiQ29udHJvbCIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBjb25kaXRpb24gPSBjKCJjb252IiwgIm1vcmVDbGVhciIpCiAgICApLAogICAgcmVfZm9ybXVsYSA9IE5BCiAgKSAlPiUKICBkcGx5cjo6bXV0YXRlKFNldmVyaXR5ID0gZmFjdG9yKAogICAgU2V2ZXJpdHksCiAgICBsZXZlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICApLAogIGNvbmRpdGlvbiA9IGZhY3Rvcihjb25kaXRpb24sCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImNvbnYiLCJtb3JlQ2xlYXIiKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiY29udmVyc2F0aW9uYWwiLCAiY2xlYXIiKSkpCgpwbG90X2dyYW5kTWVhbl9hVlNBIDwtIGdncGxvdChkYXRhX3Bvc3Rlcmlvcl9hVlNBLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IC5lcHJlZCwgeSA9IFNldmVyaXR5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGNvbmRpdGlvbikpICsKICBzdGF0X2hhbGZleWUoKSArCiAgZ2dva2FiZWl0bzo6c2NhbGVfZmlsbF9va2FiZV9pdG8oKSArCiAgbGFicyh4ID0gIlByZWRpY3RlZCBWU0EgKGluIEJhcmspIiwgeSA9IE5VTEwsCiAgICAgICBmaWxsID0gIkNvbmRpdGlvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJQb3N0ZXJpb3IgcHJlZGljdGlvbnMiKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwyMCkpICsKICB0aGVtZV9jbGVhbigpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmRhdGFfbWVfYVZTQSA8LSBtb2RlbF9hVlNBICU+JQogIGVtbWVhbnM6OmVtbWVhbnMoIH4gY29uZGl0aW9uIHwgU2V2ZXJpdHksCiAgICAgICAgICAgICAgICAgICAgI2F0ID0gbGlzdChTZXZlcml0eSA9ICJQcm9mb3VuZCIpLAogICAgICAgICAgICAgICAgICAgIGVwcmVkID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gTkEsCiAgICAgICAgICAgICAgICAgICAgKSAlPiUKICBlbW1lYW5zOjpjb250cmFzdChtZXRob2QgPSAicmV2cGFpcndpc2UiKSAlPiUKICBnYXRoZXJfZW1tZWFuc19kcmF3cygpCgoKcGxvdF9hbWVfYVZTQSA8LSBnZ3Bsb3QoZGF0YV9tZV9hVlNBLCBhZXMoeCA9IC52YWx1ZSwgeSA9IFNldmVyaXR5KSkgKwogIHN0YXRfaGFsZmV5ZShmaWxsID0gZ2dva2FiZWl0bzo6cGFsZXR0ZV9va2FiZV9pdG8ob3JkZXIgPSA3KSkgKwogIGxhYnMoeCA9ICJBdmVyYWdlIG1hcmdpbmFsIGVmZmVjdCBvZiBjb25kaXRpb24iLAogICAgICAgeSA9IE5VTEwsCiAgICAgICBzdWJ0aXRsZSA9ICJDb25kaXRpb24gZWZmZWN0IChjbGVhciAtIGNvbnZlcnNhdGlvbmFsKSIpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHRoZW1lX2NsZWFuKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKIyBDb21iaW5lZCBwbG90CnBsb3RfYVZTQSA8LSAocGxvdF9ncmFuZE1lYW5fYVZTQSB8IHBsb3RfYW1lX2FWU0EpICsKICBwbG90X2Fubm90YXRpb24odGl0bGUgPSAiQWNvdXN0aWMgVm93ZWwgU3BhY2UgQXJlYSAoVlNBKSIsCiAgICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIlByZWRpY3RlZCBWU0EgKGluIEJhcmspIGFjcm9zcyBncm91cC9zZXZlcml0eSBhbmQgc3BlYWtpbmcgY29uZGl0aW9ucy4iLAogICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lX2NsZWFuKCkpCmdnc2F2ZSgKICBwbG90ID0gcGxvdF9hVlNBLAogIGZpbGVuYW1lID0gIlBsb3RzL3Bsb3RfYVZTQS5wbmciLAogIGhlaWdodCA9IDYsCiAgd2lkdGggPSA4LAogIHVuaXQgPSAiaW4iLAogIHNjYWxlID0gMSwKICBiZyA9ICJ3aGl0ZSIKKQpgYGAKCiMjIEtpbmVtYXRpYyBEaXN0YW5jZQpLaW5lbWF0aWMgZGlzdGFuY2Ugd2FzIG1lYXN1cmVkIGZyb20gdGhlIHRvbmd1ZSBiYWNrIHNlbnNvciAoYWRoZXJlZCA1IG1tIGZyb20gdGhlIHRvbmd1ZSB0aXApIGR1cmluZyB0aGUgZGlwaHRob25nIC9haS8gaW4gImJ1eSIuIFRoZSAyRCBwb3NpdGlvbnMgb2YgdGhlIG9uc2V0IGFuZCBvZmZzZXQgd2VyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgRXVjbGlkZWFuIGRpc3RhbmNlLiBUaGlzIG1lYXN1cmUgcmFuZ2VzIGZyb20gMC4wMyB0byAyOCBtbS4gU28sIGl0IGlzIGJvdW5kIGJ5IDAsIGFuZCBkb2VzIG5vdCBoYXZlIGFueSBuZWdhdGl2ZSB2YWx1ZXMuIEZvciB0aGlzIHJlYXNvbiwgd2UgdXNlIHRoZSBsb2dub3JtYWwgZmFtaWx5LgojIyMgTG9hZGluZyB0aGUgZGF0YQpgYGB7cn0KYWlNZWFzdXJlcyA8LQogIHJpbzo6aW1wb3J0KGZpbGUgPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0F1c3RpblJUaG9tcHNvbi9tdWx0aWRvbWFpbi12b3dlbEFydGljLVBEL21haW4vRGF0YS9QcmVwcGVkRGF0YS9Db2xsYXRlZERhdGEvVGFyZ2V0TWVhc3VyZXNfYWlNZWFzdXJlcy5jc3YiKSAlPiUKICBkcGx5cjo6ZmlsdGVyKGNvbmRpdGlvbiAhPSAibGVzc0NsZWFyIikgJT4lICMgV2Ugd29uJ3QgdXNlIHRoZSBsZXNzIGNsZWFyIGNvbmRpdGlvbiBpbiB0aGlzIHN0dWR5CiAgCiMgSGVyZSB3ZSByZW5hbWUgc29tZSB2YXJpYWJsZXMgYW5kIGNsZWFuIHVwIHRoZSBmYWN0b3JzCiAgZHBseXI6Om11dGF0ZShTZXggPSBmYWN0b3IoU2V4LCBsZXZlbHMgPSBjKCJNIiwgIkYiKSksCiAgICAgICAgICAgICAgICBjb25kaXRpb24gPSBmYWN0b3IoY29uZGl0aW9uLCBsZXZlbHMgPSBjKCJjb252IiwgIm1vcmVDbGVhciIpKSkgJT4lCiAgCiAgIyBOb3cgd2UgbWVyZ2UgdGhlIGRhdGEgd2l0aCB0aGUgc3BlYWtlckxpc3QsIHdoaWNoIGhhcyBpbmZvcm1hdGlvbiBhYm91dCBzZXZlcml0eSBsZXZlbC4KICBiYXNlOjptZXJnZSguLCBzcGVha2VyTGlzdCAlPiUKICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoU3R1ZHlJRCwgU2V2ZXJpdHkpKSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgU2V2ZXJpdHkgPSBmYWN0b3IoCiAgICAgIFNldmVyaXR5LAogICAgICBsZXZlbHMgPSBjKCJIQyIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpLAogICAgICBsYWJlbHMgPSBjKCJDb250cm9sIiwgIk1pbGQiLCAiTW9kZXJhdGUiLCAiU2V2ZXJlIiwgIlByb2ZvdW5kIikKICAgICkKICApICU+JQogIGRwbHlyOjpncm91cF9ieShTdHVkeUlELCBHcm91cCwgU2V4LCBTZXZlcml0eSwgY29uZGl0aW9uKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlKGtpbkRpc3RhbmNlID0gbWVhbihraW5EaXN0YW5jZSwgbmEucm0gPSBUKSkgJT4lCiAgZHBseXI6OnVuZ3JvdXAoKQoKIyBMZXRzIHZpc3VhbGl6ZSB0aGUgb3V0Y29tZSBtZWFzdXJlLCBraW5EaXN0YW5jZQpoaXN0KGFpTWVhc3VyZXMka2luRGlzdGFuY2UpCmhpc3QobG9nKGFpTWVhc3VyZXMka2luRGlzdGFuY2UgKyAxKSkKCmRhdGFfbW9kZWxEYXRhX2tpbkRpc3RhbmNlIDwtIGFpTWVhc3VyZXMgJT4lCiAgZHBseXI6Om11dGF0ZShraW5EaXN0YW5jZSA9IGtpbkRpc3RhbmNlICsgMSkgIyBhcHBseWluZyBhIGNvbnN0YW50IGJlZm9yZSB0aGUgbG9nIHRyYW5zZm9ybWF0aW9uIGluIHRoZSBtb2RlbAoKcGVyZm9ybWFuY2U6OmNoZWNrX2Rpc3RyaWJ1dGlvbihkYXRhX21vZGVsRGF0YV9raW5EaXN0YW5jZSRraW5EaXN0YW5jZSkKaGlzdChsb2coZGF0YV9tb2RlbERhdGFfa2luRGlzdGFuY2Uka2luRGlzdGFuY2UpKQoKIyBUYWtpbmcgb3V0IHRoZSB0cmFzaApybShhaU1lYXN1cmVzKQpgYGAKCiMjIyBQcmlvcnMKRmlyc3QsIHdlIG5lZWQgdG8gZmlndXJlIG91dCB0aGUgbW9kZWwgcGFyYW1ldGVycwpgYGB7cn0KCm1vZGVsRm9ybXVsYV9raW5EaXN0YW5jZSA8LQogIGtpbkRpc3RhbmNlIH4gU2V2ZXJpdHkgKiBjb25kaXRpb24gKwogICgxIHwgU3R1ZHlJRCkgIyBFYWNoIFNwZWFrZXIgKFN0dWR5SUQpIGhhcyAyIGtpbkRpc3RhbmNlIG1lYXN1cmVzIGZvciBlYWNoIGNvbmRpdGlvbgoKYnJtczo6Z2V0X3ByaW9yKGZvcm11bGEgPSBtb2RlbEZvcm11bGFfa2luRGlzdGFuY2UsCiAgICAgICAgICAgICAgICBkYXRhID0gZGF0YV9tb2RlbERhdGFfa2luRGlzdGFuY2UsCiAgICAgICAgICAgICAgICBmYW1pbHkgPSBsb2dub3JtYWwpCmBgYAoKTm93IHdlIGNhbiBzcGVjaWZ5IHdlYWtseSBpbmZvcm1hdGl2ZSBwcmlvcnMuCmBgYHtyfQpwcmlvcnNfa2luRGlzdGFuY2UgPC0gYygKICBwcmlvcihub3JtYWwoMCwgMTApLCBjbGFzcyA9IEludGVyY2VwdCksCiAgcHJpb3Iobm9ybWFsKDAsIDEwKSwgY2xhc3MgPSBiKSwKICBwcmlvcihjYXVjaHkoMCwgMTApLCBjbGFzcyA9IHNpZ21hKSwKICBwcmlvcihjYXVjaHkoMCwgMTApLCBjbGFzcyA9IHNkKQopCmBgYAoKIyMjIEJ1aWxkaW5nIHRoZSBtb2RlbApgYGB7cn0KbW9kZWxfa2luRGlzdGFuY2UgPC0gYnJtczo6YnJtKAogIGZvcm11bGEgPSBtb2RlbEZvcm11bGFfa2luRGlzdGFuY2UsCiAgZGF0YSA9IGRhdGFfbW9kZWxEYXRhX2tpbkRpc3RhbmNlLAogIGZhbWlseSA9IGxvZ25vcm1hbCwKICBwcmlvciA9IHByaW9yc19raW5EaXN0YW5jZSwKICBjaGFpbnMgPSA0LAogIGNvcmVzID0gNCwKICBpdGVyID0gNDAwMCwKICB3YXJtdXAgPSAxMDAwLAogIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45NSksCiAgZmlsZSA9ICJNb2RlbHMvYnJtc19raW5EaXN0YW5jZS5yZHMiLAogIGZpbGVfcmVmaXQgPSAib25fY2hhbmdlIgopCmBgYAoKCiMjIyBNb2RlbCBTdW1tYXJ5CmBgYHtyfQojIFByb2JhYmlsaXR5IG9mIGRpcmVjdGlvbiAocGQpCnBkX2tpbkRpc3RhbmNlIDwtIGJheWVzdGVzdFI6OnBfZGlyZWN0aW9uKG1vZGVsX2tpbkRpc3RhbmNlKSAlPiUKICBkcGx5cjo6cmVuYW1lKHRlcm0gPSBQYXJhbWV0ZXIsCiAgICAgICAgICAgICAgICBlZmZlY3QgPSBFZmZlY3RzLAogICAgICAgICAgICAgICAgY29tcG9uZW50ID0gQ29tcG9uZW50KSAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgY29tcG9uZW50ID0gaWZlbHNlKGNvbXBvbmVudCA9PSAiY29uZGl0aW9uYWwiLCAiY29uZCIsIGNvbXBvbmVudCksCiAgICB0ZXJtID0gZ3N1YihwYXR0ZXJuID0gImJfIiwgcmVwbGFjZW1lbnQgPSAiIiwgdGVybSksCiAgICB0ZXJtID0gaWZlbHNlKHRlcm0gPT0gIkludGVyY2VwdCIsICIoSW50ZXJjZXB0KSIsIHRlcm0pKQoKIyBNb2RlbCByZXN1bHRzCm1vZGVsU3VtbWFyeV9raW5EaXN0YW5jZSA8LSB0aWR5KG1vZGVsX2tpbkRpc3RhbmNlKSAlPiUKICBkcGx5cjo6cmVuYW1lKGxfOTVfQ0kgPSBjb25mLmxvdywKICAgICAgICAgICAgICAgIHVfOTVfQ0kgPSBjb25mLmhpZ2gpICU+JQogIGRwbHlyOjptdXRhdGUob3JkZXIgPSByb3dfbnVtYmVyKCkpICU+JQogIGJhc2U6Om1lcmdlKC4scGRfa2luRGlzdGFuY2UsIGFsbCA9IFQpICU+JQogIGRwbHlyOjphcnJhbmdlKG9yZGVyKSAlPiUKICBkcGx5cjo6c2VsZWN0KCFvcmRlcikgJT4lCiAgZHBseXI6Om11dGF0ZSgKICAgIHJvYnVzdCA9IGNhc2Vfd2hlbigKICAgICAgYXMuaW50ZWdlcighKGxfOTVfQ0kgPD0gMCAmIHVfOTVfQ0kgPiAwKSkgPT0gMSAmIHBkID4gLjk1IH4gInJvYnVzdCIsCiAgICAgIFRSVUUgfiAibm90IHJvYnVzdCIKICAgICkKICApCgpybShwZF9raW5EaXN0YW5jZSkKYGBgCiMjIyBNb2RlbCBEaWFnbm9zdGljcwpgYGB7cn0KIyBBc3Nlc3MgY2hhaW4gbWl4aW5nCnBsb3RfY2hhaW5NaXhfa2luRGlzdGFuY2UgPC0gYmFzZTo6cGxvdChtb2RlbF9raW5EaXN0YW5jZSwgYXNrPUZBTFNFKQoKIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVjawpwbG90X3BwQ2hlY2tfa2luRGlzdGFuY2UgPC0gYnJtczo6cHBfY2hlY2sobW9kZWxfa2luRGlzdGFuY2UsIG5kcmF3cyA9IDEwMDApCgojIFBsb3QgY29uZGl0aW9uYWwgZWZmZWN0cwpwbG90X2NvbmRpdGlvbmFsRWZmZWN0c19raW5EaXN0YW5jZSA8LSBiYXNlOjpwbG90KGNvbmRpdGlvbmFsX2VmZmVjdHMobW9kZWxfa2luRGlzdGFuY2UpLCBhc2sgPSBGQUxTRSkKCiMga2luRGlzdGFuY2VlcnZhbCBFc3RpbWF0aW9ucwpkYXRhX3Bvc3Rlcmlvcl9raW5EaXN0YW5jZSA8LSBhcy5tYXRyaXgobW9kZWxfa2luRGlzdGFuY2UpICU+JQogIGFzLmRhdGEuZnJhbWUoKQoKcGxvdF9pbnRlcnZhbEVzdF9raW5EaXN0YW5jZSA8LSBtY21jX2FyZWFzKAogIGRhdGFfcG9zdGVyaW9yX2tpbkRpc3RhbmNlLAogIHBhcnMgPSBmaXhlZF9lZmZlY3RzIDwtIGRhdGFfcG9zdGVyaW9yX2tpbkRpc3RhbmNlICU+JQogICAgYXMuZGF0YS5mcmFtZSgpICU+JQogICAgZHBseXI6OnNlbGVjdChzdGFydHNfd2l0aCgiYl8iKSkgJT4lCiAgICBjb2xuYW1lcygpLAogICMgYXJiaXRyYXJ5IHRocmVzaG9sZCBmb3Igc2hhZGluZyBwcm9iYWJpbGl0eSBtYXNzCiAgcHJvYiA9IDAuOTUKKSAKCmBgYAoKCiMjIyBWaXN1YWxpemF0aW9ucwpgYGB7cn0KCiMgR2VuZXJhdGUgZXhwZWN0ZWQgcHJlZGljdGlvbnMgZnJvbSB0aGUgcG9zdGVyaW9yCmRhdGFfcG9zdGVyaW9yX2tpbkRpc3RhbmNlIDwtIG1vZGVsX2tpbkRpc3RhbmNlICU+JQogIHRpZHliYXllczo6ZXByZWRfZHJhd3MoCiAgICBuZXdkYXRhID0gdGlkeXI6OmV4cGFuZF9ncmlkKAogICAgICBTZXZlcml0eSA9IGMoIkNvbnRyb2wiLCAiTWlsZCIsICJNb2RlcmF0ZSIsICJTZXZlcmUiLCAiUHJvZm91bmQiKSwKICAgICAgY29uZGl0aW9uID0gYygiY29udiIsICJtb3JlQ2xlYXIiKQogICAgKSwKICAgIHJlX2Zvcm11bGEgPSBOQQogICkgJT4lCiAgZHBseXI6Om11dGF0ZShTZXZlcml0eSA9IGZhY3RvcigKICAgIFNldmVyaXR5LAogICAgbGV2ZWxzID0gYygiQ29udHJvbCIsICJNaWxkIiwgIk1vZGVyYXRlIiwgIlNldmVyZSIsICJQcm9mb3VuZCIpCiAgKSwKICBjb25kaXRpb24gPSBmYWN0b3IoY29uZGl0aW9uLAogICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJjb252IiwibW9yZUNsZWFyIiksCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImNvbnZlcnNhdGlvbmFsIiwgImNsZWFyIikpKQoKcGxvdF9ncmFuZE1lYW5fa2luRGlzdGFuY2UgPC0gZ2dwbG90KGRhdGFfcG9zdGVyaW9yX2tpbkRpc3RhbmNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IC5lcHJlZCwgeSA9IFNldmVyaXR5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGNvbmRpdGlvbikpICsKICBzdGF0X2hhbGZleWUoKSArCiAgZ2dva2FiZWl0bzo6c2NhbGVfZmlsbF9va2FiZV9pdG8oKSArCiAgbGFicyh4ID0gIlByZWRpY3RlZCBraW5lbWF0aWMgZGlzdGFuY2UgKG1tKSIsIHkgPSBOVUxMLAogICAgICAgZmlsbCA9ICJDb25kaXRpb24iLAogICAgICAgc3VidGl0bGUgPSAiUG9zdGVyaW9yIHByZWRpY3Rpb25zIikgKwogIHNjYWxlX3lfZGlzY3JldGUobGltaXRzID0gcmV2KSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNDMpKSArCiAgdGhlbWVfY2xlYW4oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpkYXRhX21lX2tpbkRpc3RhbmNlIDwtIG1vZGVsX2tpbkRpc3RhbmNlICU+JQogIGVtbWVhbnM6OmVtbWVhbnMoIH4gY29uZGl0aW9uIHwgU2V2ZXJpdHksCiAgICAgICAgICAgICAgICAgICAgZXByZWQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSwKICAgICAgICAgICAgICAgICAgICApICU+JQogIGVtbWVhbnM6OmNvbnRyYXN0KG1ldGhvZCA9ICJyZXZwYWlyd2lzZSIpICU+JQogIGdhdGhlcl9lbW1lYW5zX2RyYXdzKCkKCgpwbG90X2FtZV9raW5EaXN0YW5jZSA8LSBnZ3Bsb3QoZGF0YV9tZV9raW5EaXN0YW5jZSwgYWVzKHggPSAudmFsdWUsIHkgPSBTZXZlcml0eSkpICsKICBzdGF0X2hhbGZleWUoZmlsbCA9IGdnb2thYmVpdG86OnBhbGV0dGVfb2thYmVfaXRvKG9yZGVyID0gNykpICsKICBsYWJzKHggPSAiQXZlcmFnZSBtYXJnaW5hbCBlZmZlY3Qgb2YgY29uZGl0aW9uIiwKICAgICAgIHkgPSBOVUxMLAogICAgICAgc3VidGl0bGUgPSAiQ29uZGl0aW9uIGVmZmVjdCAoY2xlYXIgLSBjb252ZXJzYXRpb25hbCkiKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICB0aGVtZV9jbGVhbigpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCiMgQ29tYmluZWQgcGxvdApwbG90X2tpbkRpc3RhbmNlIDwtIChwbG90X2dyYW5kTWVhbl9raW5EaXN0YW5jZSB8IHBsb3RfYW1lX2tpbkRpc3RhbmNlKSArCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIktpbmVtYXRpYyBEaXN0YW5jZSIsCiAgICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gIlByZWRpY3RlZCBraW5lbWF0aWMgZGlzdGFuY2UgKG1tKSBmb3IgL2HJqi8gYWNyb3NzIGdyb3VwL3NldmVyaXR5IGFuZCBzcGVha2luZyBjb25kaXRpb25zLiIsCiAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWVfY2xlYW4oKSkKZ2dzYXZlKAogIHBsb3QgPSBwbG90X2tpbkRpc3RhbmNlLAogIGZpbGVuYW1lID0gIlBsb3RzL3Bsb3Rfa2luRGlzdGFuY2UucG5nIiwKICBoZWlnaHQgPSA2LAogIHdpZHRoID0gOCwKICB1bml0ID0gImluIiwKICBzY2FsZSA9IDEsCiAgYmcgPSAid2hpdGUiCikKYGBgCgoKIyBNb2RlbCBUYWJsZXMKYGBge3J9CnNqUGxvdDo6dGFiX21vZGVsKG1vZGVsX2FWU0EsCiAgICAgICAgICAgICAgICAgIGZpbGUgPSAiVGFibGVzL21vZGVsSW50Lmh0bWwiKQpgYGAKCg==